Websocket协议

一、Websocket协议简介

WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。

WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

1. Websocket和HTTP

  • HTTP只能是浏览器向服务端发送请求,Websocket还可以是服务端主动向客户端推送数据。
  • HTTP是无连接的,Websocket是长连接的。
  • Websocket对协议的内容没有规定,只限制协议的格式,适合用于自定义通信协议。
  • Websocket在TCP建立连接之后,还需要一次握手,采用HTTP协议格式完成Handshark。
  • Websocket使用ws或wss的同一资源标志符,类似于HTTPS,其中wss表示建立在TLS之上的Websocket。
  • 默认情况下,Websocket协议使用80端口;运行在TLS之上时,默认使用443端口。

2. Websocket的协议格式

 

 

 对于协议格式的各个bit,在参考文档第28页中有详细介绍。

从第0个字节开始,第1个字节的高七位(Payload len(7))表示Payload Data的长度,只能表示0-125。

当Payload len(7)为126时,Payload Data的长度由Payload len(7)之后的两个字节表示,unsigned short。

当Payload len(7)为127时,Payload Data的长度由Payload len(7)之后的八个字节表示,且最高位必须为0,相当于64位机上的long long。

3. Websocket的一次握手

Websocket在TCP建立连接完成后,还需要进行一次握手,用于验证合法性。

Handshark的数据格式为HTTP,格式相对固定。

3.1 一个典型的Websocket握手请求如下:

客户端请求

GET / HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: example.com
Origin: http://example.com
Sec-WebSocket-Key: sN9cRrP/n9NdMgdcy2VJFQ==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13

服务器回应

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: fFBooB7FAkLlXgRSz0BT3v4hq5s=
Sec-WebSocket-Protocol: chat
  •  Connection 必须设置 Upgrade,表示客户端希望连接升级。
  • Upgrade 字段必须设置 Websocket,表示希望升级到 Websocket 协议。
  • Sec-WebSocket-Key 是客户端生成的随机的字符串,服务器端会根据这个字段返回Sec-WebSocket-Accept字段。
  • Sec-WebSocket-Protocol是一个用户定义的字符串,用来区分同URL下,不同的服务所需要的协议。
  • Sec-WebSocket-Version 表示支持的 Websocket 版本。RFC6455 要求使用的版本是 13,之前草案的版本均应当弃用。
  • Origin 字段是可选的,通常用来表示在浏览器中发起此 Websocket 连接所在的页面,类似于 Referer。但是,与 Referer 不同的是,Origin 只包含了协议和主机名称。
  • 其他一些定义在 HTTP 协议中的字段,如 Cookie 等,也可以在 Websocket 中使用。

3.2 Sec-WebSocket-Accept的计算

Sec-WebSocket-Accept字段的值是服务器根据客户端发送的Sec-WebSocket-Key字段的值计算得到的。

RFC6455提供了一个固定的GUID("258EAFA5-E914-47DA-95CA-C5AB0DC85B11")参与计算。

计算过程如下:

  • sha_value = SHA1(Sec-WebSocket-Accept+GUID)
  • Sec-WebSocket-Accept = base64_encode(sha_value )

4. Payload传输

Payload内容的传输可以是明文或密文,由MASK字段设定。该字段为1表示密文传输。

密钥为Masking-Key字段的32bits数据。

加解密算法为:(原始数据D,结果数据E,密钥为K[4]以字节为单位)

for(int i = 0; i < D.length; ++i)

  E = D^K[i%4]

5. FIN标志位

指示这是消息中的最后一个片段。第一个片段也可能是最后的片段。

6. opcode标志位

定义“有效载荷数据”的解释。如果一个未知的opcode被接收时,接收端必须失败WebSocket Connection_。定义了以下值。

* %x0表示延续帧

* %x1表示文本框

* %x2表示二进制坐标系

* %x3-7被预留给其他非控制帧

* %x8表示连接关闭

* %x9表示一个ping

* %xA表示pong

* %xB-F预留给进一步的控制帧

----------------------------------------------------------------------------------------------------

参考文档:websocket_rfc6455

github:https://github.com/illusorycat/Websocket.git

posted @ 2022-03-11 18:32  幻cat  阅读(520)  评论(0编辑  收藏  举报