websocket协议解析[RFC6455]

阅读数:91 评论数:0

跳转到新版页面

分类

网络/通信

正文

连接时握手

websocket的握手实际上就是给服务器发送一个GET请求,里面带上指定的header即可。

1、request例子:

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

(1)upgrade和Connection是请求握手时固定要填写的两个键值对。

(2)Sec-WebSocket-Key是一个16位的随机值,经过base64编码后生成。

(3)Sec-WebSocket-Version是使用的版本号。

(4)Sec-WebSocket-Protocol是选用的子协议,为可选字段,子协议是由websocket承载的协议。

2、response例子:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

(1)状态码为101的响应

(2)Sec-WebSocket-Accept是服务端利用Key和UUID拼接后再进行base64编码产生的一个值,客户端可进行验证。

这样,连接时握手就完成了。

数据帧

1、基础帧协议

因为一些安全的原因,从客户端发送到服务端的帧全部要与掩码进行异或运算过才有效,而服务端发送到客户端的帧不需要进行异或运算。

名称 长度 注释
FIN 1bit 标明这一帧是否是整个消息体的最后一帧
RSV1 RSV2 RSV3 1bit 保留位,必须为0,如果不为0,则标记为连接失败
opcode 4bit 定义这一帧的类型
MASK 1bit 标明承载的内容是否需要用掩码进行异或
Masking-key 0或4bytes 掩码异或运算用的key
Payload length 7bit or 7+16bit or 7+64bit 承载体的长度

 

2、opcode

数据包大体可分为两种,一种是字符数据包(string), 一种是字节数据包(byte)。

定义
%x0 continuation frame,表明这个数据包是上一个数据包的延续。
%x1 text frame,数据包是一个字符帧
%x2 binary frame,数据包是一个字节帧
%x3-7 预留,非控制帧使用
%x8 关闭连接
%x9 ping,心跳请求
%xA pong,心跳响应
%B-F 预留,供制帧使用

 

3、MASK

如果是客户端发送到服务端的数据包,我们需要使用掩码对payload的每一个字节进行异或运算,生成masked payload才能被服务器读取。

具体的运算其实很简单。

假设payload长度为pLen,mask-key长度为mLen,i作为payload的游标,j作为mask-key的游标,伪代码如下:

for (i = 0; i < pLen; i++){
    int j = i % mLen;
    maskedPayload[i] = payload[i] ^ maskKey[j];
}

 

4、payload长度

读取负载数据,需要知道读到哪里为止,这个过程稍微有点复杂:

(1)读取9-15位(包括9和15位本身),并转换为无符号整数,如果值小于或等于125,这个值就是长度;如果是126,请转到步骤2。如果127,请转到步骤3。

(2)读取接下来的16位并转换为无符号整数,并作为长度。

(3)读取接下来的64位并转换为无符号整数,并作为长度。

 

关闭连接时的握手

关闭连接的时候,只用发送一个opcode为0x08的帧,payload中前2个字节写入定义code,后续写入关闭连接的reason。




相关推荐