思维导图
1. 为什么要使用WebSocket
为什么要使用WebSocket协议?它跟 HTTP 协议有什么不同?
因为HTTP协议的通信只能由客户端发起,对于想要双向通信的服务而言,如聊天室等,就会有性能瓶颈,鉴于此,WebSocket 就这样闪亮登场,提升Web的浏览速度。
2. 什么是WebSocket
WebSocket,即 Web 浏览器与 Web 服务器之间全双工通信标准。其中,WebSocket 协议由 IETF 定为标准,WebSocket API 由W3C定为标准。
2.1. WebSocket协议
Web 服务器与客户端之间建立起 WebSocket 协议的通信连接,之后所有的通信都依靠这个专用协议进行。通信过程中可互相发送 JSON、XML、HTML 或图片等任意格式的数据。
由于是建立在 HTTP 基础上的协议,因此连接的发起方仍是客户端,而一旦确立 WebSocket 通信连接,不论服务器还是客户端,任意一方都可直接向对方发送报文。
WebSocket协议有以下的特点:
-
WebSocket协议建立在 TCP 协议之上。
-
与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
-
同源策略不适用于WebSocket,因此可以打开到任意站点的连接。
-
推送功能:支持由服务器向客户端推送数据的推送功能。这样,服务器可直接发送数据,而不必等待客户端的请求。
-
减少通信量:只要建立起 WebSocket 连接,就希望一直保持连接状态。和 HTTP 相比,不但每次连接时的总开销减少,而且由于 WebSocket 的首部信息很小,通信量也相应减少了。
WebSocket首部
WebSocket首部的格式如下,相较于HTTP协议的定义,数据量比较小。
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|I|S|S|S| (4) |A| (7) | (16/64) |
|N|V|V|V| |S| | (if payload len==126/127) |
| |1|2|3| |K| | |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
| Extended payload length continued, if payload len == 127 |
+ - - - - - - - - - - - - - - - +-------------------------------+
| |Masking-key, if MASK set to 1 |
+-------------------------------+-------------------------------+
| Masking-key (continued) | Payload Data |
+-------------------------------- - - - - - - - - - - - - - - - +
: Payload Data continued ... :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Payload Data continued ... |
+---------------------------------------------------------------+
2.2. WebSocket API
WebSocket API 由 W3C定为标准。JavaScript可调用 WebSocket 程序接口,以实现 WebSocket 协议下全双工通信。
var socket = new WebSocket('ws://game.example.com:12010/updates');
- 必须给WebSocket构造函数传入一个绝对的URL
- 同源策略不适用于WebSocket,因此可以打开到任意站点的连接
3.WebSocket的工作过程
为了实现 WebSocket 通信,在 HTTP 连接建立之后,需要完成一次握手的步骤。
3.1. HTTP 阶段
HTTP请求的Request
Origin字段表示这本身是一个HTTP请求Connection字段的值为Upgrade,告知服务器通信协议发生改变Upgrade字段的值为websocket,表示通信协议发生改变,改为websocket,以达到握手的目的。
HTTP请求的Response
- 对于之前的请求,返回状态码
101 Switching Protocols的响应。
3.2. WebSocket 阶段
成功握手确立 WebSocket 连接之后,通信时不再使用 HTTP 的数据 帧,而采用 WebSocket 独立的数据帧。
- 绿色的表示客户端发送给服务器端的数据
- 红色的表示服务器端发送给客户端的数据
- 在此过程中,连接一直保持畅通
4 示例:在线的答案之书
答案之书是一本神奇的书,你想问的所有问题都可以在这本书中找到答案。默默想到一个问题,然后翻开这本书,随便找到一页,这页上就有你所想问题的答案。
那么要是有一本线上的答案之书,那就更方便了?该如何使用WebSocket实现一本线上的答案之书?
在页面input框里输入你的问题,然后点击interactbutton与服务器交互,寻求答案。还可以只点击readingbutton,看到源源不断的答案
4.1. 效果图
4.2. 客户端
客户端实现的主要代码如下:
// main code part
const socket = new WebSocket(`ws://localhost:8080/chinese`);
const interactButton = document.getElementById('interact');
interactButton.addEventListener('click', () => {
const value = document.getElementById('input').value;
//客户端给服务器发送消息
socket.send(value);
})
ws wss表示这是一个WebSocket请求,其中wss类似于https,带加密的socket.send()是给服务器发送消息的方法
4.3 服务器端
服务器端实现的主要代码如下:
// main code part
const ws = require('ws');
const http = require('http');
const {parse} = require("url");
const server = http.createServer();
const wss = new ws.WebSocketServer({noServer: true});
wss.on('connection', (ws, req) => {
const { pathname } = parse(req.url);
const language = pathname === '/english' ? 'english' : 'chinese';
ws.on('message', function message(data) {
// 服务器发送消息给客户端
ws.send(resultMsg);
});
});
server.listen(8080, () => {
console.log(`listening port at ${PORT}...`);
});
- 服务器端的代码引入了
http模块,使用http模块创建了server服务,然后监听在8080端口 wss服务监听connection,当有客户端的消息来到时,服务器发送消息返回,同样使用的是send方法