WebSocket备忘
记些websocket的知识备忘。
对比HTTP优势
websocket与HTTP一样,都是建立TCP之上的应用层协议,它较于HTTP的优点主要有以下两点:
- 全双工
HTTP不允许服务端主动向client发送数据,websocket在设计之初着重考虑了这个问题,所以websocket支持全双工通信,服务端可以主动给客户端推送消息
- 传输更有效率
- HTTP经常需要建立TCP连接(keep-alive可以部分解决),而websocket始终使用一个TCP来保持通信,在传输数据的过程中可以节省建立TCP连接的费时,以及避免TCP慢启动对速度的影响
- 基于消息分帧且支持二进制的数据传输,在很多情景下相较于HTTP有效率优势
连接建立过程
websocket作为HTTP不能主动推送的替代方案,其连接建立过程却依赖HTTP完成,主要原因是为了与现有HTTP基础设施兼容。使用HTTP建立连接可以复用80和443端口,因为这两个端口是被认可的,不太可能出现被中间设备或服务器防火墙拦截的情况。
通过HTTP建立连接的好处除了复用端口外,可以重用HTTP的Upgrade流,并扩展HTTP头部字段完成建立连接的信息协商。
握手过程
建立连接的握手过程主要是以下两步:
- 客户端发出一个HTTP请求并携带Connection、Upgrade等头部,与此同时还携带了一些扩展头部如Sec-WebSocket-Key、Sec-WebSocket-Protocol等
- 服务端收到请求,如果支持websocket协议则返回状态码101表示切换协议,并且返回与客户端一致Connection、Upgrade头部外加部分与websocket连接建立有关的扩展头部
当上诉握手步骤成功完成后,表明websocket连接建立完成,接下来的数据通信开始由websocket协议接管。
扩展头部
部分扩展头部的含义如下:
- Sec-WebSocket-Key
客户端利用该头部携带一次性的值来验证接收到的请求服务器是否支持websocket协议,假设某代理缓存了一次握手请求的响应,当另一个client再次请求握手时,该代理没有再次请求服务器而返回了上一个请求的响应,这时客户端能判断出当前链路不支持websocket协议,从而关闭连接
- Sec-WebSocket-Accept
响应头,用于配合Sec-WebSocket-Key,服务器对client传过来的Key进行签名(配合一个全球唯一的GUID),再使用该头部携带传给客户端表明支持websocket协议
- Sec-WebSocket-Protocol
用于商议websocket通信的子协议,具体规则是client通过该头部提供一个备选列表,服务器从中选择自己支持的一个传回给client
数据帧
websocket协议通信的数据帧的结构如下:
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,表示当前帧是不是消息的最后一帧,因为websocket协议的通信单位是“消息”,对于过长的消息有可能被分为多个帧
- RSV1-3,扩展用途
- opcode,表示被传输帧的类型,一共这几种:文本(1),二进制(2),关闭(8),ping(9),pong(10)
- MASK,表示Payload Data是否有掩码,只适用客户端发送给服务端的消息
- Extended payload length,表示Payload Data的长度,有多种可能:
- 0-255,就是Payload Data的长度
- 126,接下来的2字节所表示无符号整数才是Payload Data的长度
- 127,接下来的8字节所表示无符号整数才是Payload Data的长度
- Masking-key,掩码的值
掩码的作用可以防止恶意脚本拥有tcp socket权限,避免攻击中间设备的可能,具体可以参考这篇文章
- Payload Data,净荷,也就是被帧所携带的数据