Websocket相关知识整理

Websocket 协议格式说明

最近整理项目中关于websocket中的部分,由于之前代码中websocket的功能不够完整,缺少了延续帧的数据拼接,以及mask的掩码功能。所以初步深入了一下websocket协议。

关于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:标识该数据帧是否是信息的最后一帧数据,如果为1则表明距 上一次 FIN为1 的一帧之间,这些数据是完整的一条信息。

  • RSV 1-3:默认为0,除非协商了扩展定义了非0的意义。如果接收到非0,且没有协商扩展,接收端必须使WebSocket连接失败。

  • Opcode:帧类型

    1. 0:Continuation Frame,表明该帧数据是一条完整信息的其中一帧

    2. 1:Text Frame ,这是一条文本数据

    3. 2:Binary Frame ,这是一条二进制流数据

    4. 3 - 7:为以后的非控制帧保留

    5. 8:Connection Close Frame,这是关闭websocket连接请求的数据帧

    6. 9:Ping Frame ,这是一条ping帧

    7. A:Pong Frame,这是一条pong帧

    8. B - F:为以后的控制帧保留

  • Mask:掩码,是否加密数据,为1则需要对根据一个随机的maskCode对数据进行一次位运算,一般客户端发送给服务端的数据需要用掩码加密,而服务端发给客户端的一般不需要

  • Payload:盛放该帧数据的长度,由于该字段占据7bit,所以最大为127,所以规定

    1. 如果数据长度<126,则直接将数据长度存在这7bit中
    2. 如果长度=126,则将数据长度存在接下来的2字节数据中(2字节长度可存最大无符号整数为 65535)
    3. 如果长度=127,则将数据长度存在接下来的8字节数据中
  • Extended payload length:接上个字段,这两个字段用来存放数据的长度

  • Masking-key:占据 0或4 Byte,上面的Mask字段为1,则需要生成4bit的随机值,为0则为空

  • Payload data: (x + y)字节,存放了该数据帧所有的数据。由(Extension data + Application data 构成)

    1. Extension data:x字节,保留参数,默认为0 Byte,除非协商了扩展。
    2. Application data:y字节,如果上面Extension data为0,没有协商拓展,则此字段存储了该帧所有的数据。

大小端

定义:对于一个由2个字节组成的16位整数,在内存中存储这两个字节有两种方法

  • 一种是将低序字节存储在起始地址,这称为小端(little-endian)字节序;
  • 另一种方法是将高序字节存储在起始地址,这称为大端(big-endian)字节序。

之所以关注这个问题是因为,在完善别人的Websocket协议时,当数据长度大于125的时候,我需要将真正的数据长度填充至2个字节或者8个字节的Extended payload length之中,由于采用的小端模式存储,导致服务端那边读取的数据长度一直不对,最后才发现是这个问题。


位运算

&: 与 当两个位都为1时,结果才为1
1. 清零 与一个各位都为零的数值相与,结果为零
2. 取一个数的指定位, 用另一个指定位上全为1,其余位上全为0的数与该数相与,则获得的新值就是该数的指定位
3. 判断奇偶 最未位为0则为偶数,为1则为奇数
由此 可以用if ((a & 1) == 0)代替if (a % 2 == 0)来判断a是不是偶数,因为
1的末位数为1

|: 或 当两个位都为0时,结果才为0
1. 对一个数的某些位设置为1, 用另一个指定位上全为1,其余位上全为0的数与该数相或,则获得的新值指定位上的位就为1,非指定位还是会保持不变。

^: 异或 当两个位相同则为0,相异则为1
1. 翻转指定位, 用另一个指定位上全为1,其余位上全为0的数与该数异或,则获得的新值置顶位与该数指定位上的值正好相反
2. 与0相异或值不会改变 1000 0001 ^ 0000 0000 = 1000 0001
3. 交换两个数
a = 1000 1001, b = 1101 0000
a ^= b; // a = 0101 1001
b ^= a; // b = 1000 1001
a ^= b; // a = 1101 0000
如上所示,a 与b进行两次异或后,得出的新值还是a。

~: 取反, 每一位上0 ——> 1, 1 ——> 0
该运算符的优先级比其他的要高!

<< 左移运算符 将一个数的二进制位上各个位往左移若干位(左边的位丢
弃,右边补0)
a = 1011 1010, a<< 2 = 1110 1000

若左移时舍弃的高位不包含1,则每左移一位,相当于该数乘以2。
即 0011 1010<< 2 = 1110 1000
即  0011 1010 =  58, 1110 1000 = 116

>> 右移运算符 将一个数的二进制位上各个位往右移若干位(右边的位丢
弃,正数左边补0,负数左边补1)
a = 1011 1010, a>> 2 = 0010 1110

操作数每右移一位,相当于该数除以2。
即 1011 1010 = 186
即 0010 1110 = 46

不同长度的数据进行位运算时,则按照右端对齐,左端补齐0或者1,正数或者无符号数补0,负数补1


最后

上篇文章立的flag这么快就被打脸了,这是2021年的第一篇,也希望今年有一个好的开始吧,再接再厉!

你可能感兴趣的:(Websocket相关知识整理)