WebSocket

发布于:2024-11-29 ⋅ 阅读:(14) ⋅ 点赞:(0)

握手

1 客户端发起握手请求:客户端向服务器发送一个特殊的HTTP请求,其中包含一个Upgrade字段,表明客户端希望将该连接从HTTP协议升级为WebSocket协议。请求的关键部分包括:

GET请求:客户端使用GET方法请求与WebSocket连接

  • Connection字段:值为Upgrade,指示连接要从HTTP升级。
  • Upgrade字段:值为websocket,表示升级的目标协议。
  • Sec-WebSocket-Key:随机生成的Base64编码密钥,用于握手的安全性验证。
  • Sec-WebSocket-Version:协议版本号,通常为13。

2 服务器响应握手请求:服务器接收到握手请求后,确认请求是否有效,并返回一个包含101 Switching Protocols状态码的响应,表示协议升级成功。服务器的响应包括:

  • HTTP 101状态码:101 状态码表示服务器已经理解了客户端的请求,并将通过 Upgrade 消息头通知客户端采用不同的协议来完成这个请求。
  • Upgrade字段:与客户端相同,表明升级为WebSocket协议。
  • Sec-WebSocket-Accept:根据客户端的Sec-WebSocket-Key计算出的验证密钥,用于完成握手的安全性校验。这个密钥是通过将Sec-WebSocket-Key与一个常量字符串进行拼接(258EAFA5-E914-47DA-95CA-C5AB0DC85B11),然后通过SHA-1哈希生成,再进行Base64编码得到的。

连接升级完成:握手完成后,HTTP连接升级为WebSocket连接,客户端和服务器可以通过这个持久的连接开始双向通信。

1、FIN: 占 1 个 bit

        0:不是消息的最后一个分片 1:是消息的最后一个分片

        2、RSV1, RSV2, RSV3:各占 1 个 bit一般情况下全为 0。当客户端、服务端协商采用         WebSocket 扩展时,这三个标志位可以非 0,且值的含义由扩展进行定义。如果出现非零的值,且并没有采用 WebSocket 扩展,连接出错。

3、Opcode: 4 个 bit

        %x0:表示一个延续帧。当 Opcode 为 0 时,表示本次数据传输采用了数据分片,当前收到的数据帧为其中一个数据分片;

        %x1:表示这是一个文本帧(frame);

        %x2:表示这是一个二进制帧(frame);

        %x3-7:保留的操作代码,用于后续定义的非控制帧;

        %x8:表示连接断开;

        %x9:表示这是一个 ping 操作;

        %xA:表示这是一个 pong 操作;

        %xB-F:保留的操作代码,用于后续定义的控制帧。

4、Mask: 1 个 bit 表示是否要对数据载荷进行掩码异或操作。

        0:否  1:是

5、Payload length: 7bit or 7 + 16bit or 7 + 64bit

       表示数据载荷的长度

  x 为 0~126:数据的长度为 x 字节;

       x 为 126:后续 2 个字节代表一个 16 位的无符号整数,该无符号整数的值为数据的长度;

       x 为 127:后续 8 个字节代表一个 64 位的无符号整数(最高位为 0),该无符号整数的值为数据的长度。

6、Masking-key: 0 or 4bytes

        当 Mask 为 1,则携带了 4 字节的 Masking-key;
        当 Mask 为 0,则没有 Masking-key。
7、Payload Data: 载荷数据

j = i % 4
maskkey[4]     //  j用来形容maskkey  0 1 2 3
payload[N]       // i是给payload做索引用的

payload[i] ^= maskkey[j];

每个WebSocket数据帧包含两个主要部分:帧头(Header)和有效载荷(Payload),帧头部分包含了控制信息,而有效载荷部分则是实际传输的数据。

  • FIN:表示该数据帧是否是消息的最后一个帧,值为1表示结束,0表示后续还有帧。
  • Opcode:标识该数据帧的类型,如文本帧、二进制帧等。常见的值为
    • 0x1:文本帧(UTF-8编码)
    • 0x2:二进制帧
    • 0x8:关闭帧
    • 0x9:Ping帧
    • 0xA:Pong帧
  • Mask:标识数据帧的有效载荷是否进行了掩码操作。客户端发送的帧必须带有掩码,而服务器发送的帧可以不带掩码
  • Payload Length:有效载荷的长度,值为7位或更多,具体取决于载荷的大小。
  • Masking Key:如果Mask位为1,则这个字段存在,用于解码有效载荷数据。
  • Masking Key:如果Mask位为1,则这个字段存在,用于解码有效载荷数据。

客户端发送一帧数据

服务端回复同样的数据

部分测试代码

服务端

使用acl做Websocket服务端 , 只需要在HttpServlet类里面重载doWebSocket方法就可以实现websocket协议的交互

如果要加上ssl验证 , 在创建HttpServlet之前调用conn->setup_hook即可实现wss加密,否则普通的websocket连接将失败

客户端

使用libhv做websocket客户端 , examples里面的例子相当的简单,如果需要支持wss, 则需要在连接之前调用withTLS把初始化的hssl_ctx_opt_t设置进去即可。


wss 报文

server

client

使用了ssl加密之后抓包发现多了很多TLS的报文,且看不到自己发送的明文了