WebSocket协议
WebSocket协议通信机制
WebSocket协议是独立的、基于TCP的协议。其本质是先通过HTTP/HTTPS协议进行握手后创建一个用于交换数据的TCP连接,此后服务器端与客户器端通过此TCP连接进行实时通信。
WebSocket打开握手
每个socket连接都始于一个HTTP请求,该请求包含一个特殊的首标Upgrade。Upgrade首标表示客户端会将连接升级到不同的协议。在这种情况下,这个不同的协议就是WebSocket。
发送握手请求
客户端通过HTTP协议传输WebSocket支持的版本号、HTTP协议的版本号、原始地址和主机地址等字段给服务器端。客户端发送的HTTP请求代码如下:
GET /chat HTTP 1.1
Host: server.example.com
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
这个升级的请求头增加了以下字段:
- Sec-WebSocket-Protocol:客户端可以接收的子协议的类型,即在WebSocket协议之上的应用层协议类型。
- Connection:告知服务器端当前请求连接是升级的HTTP请求。
- Origin:防止客户端使用脚本进行未授权的跨源攻击。服务器端根据这个字段判断是否接受客户端的Socket连接。可以返回一个HTTP错误状态码来拒绝连接。
- Sec-WebSocket-Key:为了表示服务器端同意和客户端进行Socket连接,服务器端需要使用该字段进行校验,然后返回一个校验过的字符串给客户端,客户端验证通过后才能正式建立Socket连接。
- Sec-WebSocket-Version:表示版本兼容性。
返回握手应答
WebSocket服务器端收到客户端发送的握手请求后,如果数据包数据和格式正确,客户端和服务器端的协议版本号匹配等,就接收本次握手链接,并给出响应的数据回复。服务器端返回的响应代码如下:
HTTP/1.0 Switching Protocols
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Accept: xxxxxxxxxxxxxxxxxxxxxxxx
Sec-WebSocket-Protocol: chat
响应代码中包含以下字段:
- Sec-WebSocket-Accept:服务器端将加密处理后的握手Key通过这个字段返回给客户端,表示同意握手建立连接。
- Sec-WebSocket-Protocol:服务器选择的一个应用层协议。
客户端收到服务器端回复的数据包后,如果数据包内容、格式都正确,就表示本次连接成功,升级为WebSocket协议,这也称作WebSocket初始握手(Opening Handshak)。
数据帧传输格式
WebSocket连接打开时,客户端和服务器端可以互相发送数据,数据使用一系列帧来传输。基本的数据帧由一个opcode、一个payload长度和发送的应用数据等组成。
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 ... |
+---------------------------------------------------------------+
- FIN:1bit,表示是消息的最后一帧。
- RSV1,RSV2,RSV3:每个1bit,必须是零,除非扩展定义为非零,如果接收到的是非零值但是扩展没有定义,则需要关闭连接。
- Opcode:4bit,解释payload数据,规定有以下不同的状态,如果未知则接收方马上关闭连接。状态如下:0x0(附加数据帧)、0x1(文本数据帧)、0x2(二进制数据帧)、0x3-7(保留为之后非控制帧使用)、0xB-F(保留位后面的控制帧使用)、0x8(关闭连接帧)、0x9(ping)、0xA(pong)。
- Mask:1bit,掩码,定义payload数据是否进行了掩码处理。
- Masking-Key: 0到4子节,掩码解密密钥,用于解码Payload Data。客户端发出的数据帧需要进行亚麻处理,所以此位是1。
- Payload length:7bit、7+16bit或7+64bit。payload Data的长度。
- Payload data:任意长度数据。包含有扩展定义数据和应用数据。
WebSocket关闭握手
正常关闭握手的步骤:
- 当一端接收到一个关闭帧,且先前没有发送关闭帧,则这一端必须发送一个关闭帧作为响应。
- 当接收到这个响应帧时,接收这一端关闭连接,同时发送表明关闭连接的控制帧,不再发送数据。
- 另一端接收到表示应该关闭连接的控制帧后,丢弃后面接收的所有数据,关闭连接。
但是TCP关闭握手并不总是端到端可靠的,特别是出现拦截代理和其他的中间设施。当WebSocket关闭时,终止连接的端点可以发送一个数字代码,以及一个表示选择关闭套接字原因的字符串。代码1000~1015规定用于WebSocket连接层。
WebSocket协议通信实现的相关技术
WebSocket构造函数
WebSocket构造函数语法格式如下:
var ws = new WebSocket("ws://127.0.0.1/WebSocket/websocket")
URL地址的字符串需要以“ws”或“wss”(加密通信时使用)作为开头。
WebSocket事件
客户端的应用程序通过监听WebSocket对象上的事件,来及时处理数据和改变连接的状态。WebSocket对象可以触发4种事件,包括
- open事件:WebSocket连接建立。
- message事件:客户端接收到服务器端的数据。
- error事件:通信过程中发生错误。
- close事件:连接关闭。
WebSocket方法
- send()方法:发送数据到服务器端。
- close()方法:关闭WebSocket连接。可选参数:code(数字型的状态代码)、reason(文本字符串)。