WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议。
介绍#
首先由客户端发起 HTTP 请求,HTTP 请求里存放 WebSocket 支持的版本号等信息,如: Upgrade、Connect、WebScoket-Version 等。
其中有一个请求头 Sec-WebScoket-Key,这是客户端使用 base64 编码的 24 位随机字符序列,用于服务器标识当前连接的客户端,同时也要求服务器响应一个同样加密的 Sec-WebScoket-Accept 头作为应答,这个用于给客户端标识。
只有当两者匹配,连接才算建立成功(服务器响应 101 状态码表示连接成功),最后借助于 TCP 传输信道进行全双工通信。
特点
- 没有同源限制
升级到 WebSocket 协议#
流程
- 客户端必须发送 Sec-WebSocket-Version 和 Sec-WebSocket-Key。
- 客户端可以通过 Sec-WebSocket-Protocol 发送应用子协议列表(不是必须)。如果客户端发送了子协议列表,服务器必须选择一个子协议并通过 Sec-WebSocket-Protocol 返回协议名,如果服务器不支持任何一个协议,连接断开。
- 客户端可以通过 Sec-WebSocket-Extensions 发送一个或多个扩展;如果服务器没有返回扩展,则连接不支持扩展。
- 服务器必须返回 Sec-WebSocket-Accept 确认协议。
第一次通过,http 升级到 web socket
请求报文
Connection: Upgrade
// 请求升级到 websocket 协议Upgrade: websocket
// 可选的客户端支持的协议扩展列表,指示了客户端希望使用的协议级别的扩展Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
//自动生成的key,已验证服务器对协议的支持,其值必须是Sec-WebSocket-Key: RfbP3GpmZpMiUaAfex5JRQ==
// 可选的应用指定的子协议列表(可以是多个,用“,”分割)Sec-WebSocket-Protocol: mqtt
//客户端使用的 websocket 协议版本,如果服务器不支持该版本,需要返回一个 Sec-WebSocket-Version,里面包含服务端支持的版本号。Sec-WebSocket-Version: 13
Sec-WebSocket-Key
由浏览器生成的,提供基本的防护,防止恶意或者无意的连接。
用于握手阶段。它从客户端发送到服务器以提供部分内容,服务器用来证明它收到的信息,并且能够有效的完成 WebSocket 握手。有助于确保服务器不会接收来自非 WebSocket 客户端的连接(例如 HTTP 客户端)被滥用发送数据到毫无防备的 WebSocket 服务器。
响应报文
// 101 响应码确认升级到 WebSocket 协议HTTP/1.1 101 Switching Protocols
// 签名的键值验证协议支持Sec-WebSocket-Accept: gp56u7lzuqL5TSEd2dbk4OmZ8UI=
//服务器选择的应用子协议Sec-WebSocket-Protocol: mqtt
Sec-WebSocket-Accept
例:客户端发送的请求报文字段 Sec-WebSocket-Key
中包含的值为 dGhlIHNhbXBsZSBub25jZQ==
,服务器把这个值与 258EAFA5-E914-47DA-95CA-C5AB0DC85B11
进行连接,然后生成 dGhlIHNhbXBsZSBub25jZQ==258EAFA5-E914-47DA-95CA-C5AB0DC85B11
字符串,进行 SHA-1 运算,生成 0xb3 0x7a 0x4f 0x2c 0xc0 0x62 0x4f 0x16 0x90 0xf6 0x46 0x06 0xcf 0x38 0x59 0x45 0xb2 0xbe 0xc4 0xea
,最后进行 base64 编码生成 s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
,然后放入响应报文的 Sec-WebSocket-Accept
字段中并响应客户端请求。
WebSocket 数据帧#
- FIN:0 表示不是最后一帧,1 表示最后一帧
- RSV1,RSV2,RSV3:一般情况下全为 0。当客户端、服务端协商采用 WebSocket 扩展时,这三个标志位可以非 0,且值的含义由扩展进行定义。如果出现非零的值且并没有采用 WebSocket 扩展,连接出错
- 操作码(Opcode):
- %x0:表示一个延续帧。当 Opcode 为 0 时,表示本次数据传输采用了数据分片,当前收到的数据帧为其中一个数据分片
- %x1:表示一个文本帧(text frame)
- %x2:表示一个二进制帧(binary frame)
- %x3-7:保留的操作代码,用于后续定义的非控制帧
- %x8:表示连接断开
- %x9:表示这是一个心跳请求(ping)
- %xA(%x10):表示这是一个心跳响应(pong)
- %xB-F:保留的操作代码,用于后续定义的控制帧
- 掩码(Mask) 表示是否对数据载荷进行掩码异或操作。1 表示需要,0 表示不需要。只适用于客户端给服务器的消息,客户端给服务器发送消息,这里一定为 1
https://blog.csdn.net/King_weng/article/details/108264798