websocket协议标准和实现
leeir 2016 10.13
client
server
ws:// Sec-WebSocket-Key
Sec-WebSocket-Accept:base64(sha1(Sec-WebSocket-Key+MASK))
1、服务端获取到"Sec-WebSocket-Key"
2、将这个key与字符串'258EAFA5-E914-47DA-95CA-C5AB0DC85B11' concat
3、对新的字符串通过sha1散列算法进行计算
4、base64编码
5、写入"Sec-WebSocket-Accept"响应给客户端
6、完成握手协议标准:解包数据帧
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 ... |
+---------------------------------------------------------------+
上图引自RFC6455 https://tools.ietf.org/html/rfc6455 细节可参考官方文档
先分析下数据帧的格式规范吧
(1字节为8个bit)
第一个字节:
FIN 1bit 表示信息的最后一帧,flag,也就是标记符
RSV 1-3 1bit 官方说是备用的默认现在都是0
Opcode 4bit 帧类型
第二个字节:
Mask 1bit 掩码,是否加密数据,默认必须置为1 (这里很蛋疼)
PayloadLength 7bit 数据的长度 7个bit位存储无符号整型的话那么就是0-127这是存储不了大的数据的
所以paload是可扩展的长度 规则为Payload length: 125以内的7 bits, 7+16 bits, or 7+64 bits
下面4个bit是maskKey但是是建立在mask为1的情况下的如果MASK!=1则没有maskKEY的掩码实体
Masking-key 1 or 4 bit 掩码
在下面全部是payload的数据部分
Payload data协议标准:打包数据帧
* opcode的对照表
* 参考 https://tools.ietf.org/html/rfc6455 11.7部分
|Opcode | Meaning | Reference |
-+--------+-------------------------------------+-----------|
| 0 | Continuation Frame | RFC 6455 |
-+--------+-------------------------------------+-----------|
| 1 | Text Frame | RFC 6455 |
-+--------+-------------------------------------+-----------|
| 2 | Binary Frame | RFC 6455 |
-+--------+-------------------------------------+-----------|
| 8 | Connection Close Frame | RFC 6455 |
-+--------+-------------------------------------+-----------|
| 9 | Ping Frame | RFC 6455 |
-+--------+-------------------------------------+-----------|
| 10 | Pong Frame | RFC 6455 |
-+--------+-------------------------------------+-----------|
0为多个frame 做分片时用到
1为字符串数据帧
2为二进制数据帧
8控制型 连接关闭
9和10为心跳检测控制 发送ping 回复pong 具有相互性 即服务端对客户端可以做心跳检测 客户端也可以对服务端做心跳检测
frame结构:
FIN: 1,//结束标识符 分片时候会体现 当为0时代表后面还有数据 1代表结束
Opcode: 1, //对应关系见上表
Mask: 1, //是否需要掩码加密
PayloadLength: 5,//payload部分数据长度
MaskingKey: [ 39, 158, 30, 16 ],//掩码实体
PayloadData: '哈哈哈 我只是一个payload'//payload数据实体编号: 0 1 .... n-2 n-1 分片: |——|——|......|——|——| FIN: 0 0 .... 0 1 Opcode: !0 0 .... 0 0
将原本一个大的帧拆分成数个小的帧
>>NOTE:
1、多个数据包但是前面几个数据帧的fin都为0最后一个为1来结束分片标识 每一帧的Opcode为0
2、消息的分片必须由发送者按给定的顺序发送给接收者
3、控制帧禁止分片
4、接受者不必按顺序缓存整个frame来处理nodejs(buffer,net,crypto)
RFC6455
nodejs-websocket
http://jinnianshilongnian.iteye.com/blog/1913795 中文版RFC6455
https://tools.ietf.org/html/rfc6455 官方文档