一、协议简介
WebSocket protocol 是HTML5一种新的协议,它是实现了浏览器与服务器全双工通信,本文主要介绍WebSocket协议格式。
WebSocket通信过程分为两步:握手请求和数据传输。
二、握手请求
1、客户端在连接请求时候发送的内容
GET / HTTP/1.1
Connection:Upgrade
Host:127.0.0.1:8088
Origin:null
Sec-WebSocket-Extensions:x-webkit-deflate-frame
Sec-WebSocket-Key:puVOuWb7rel6z2AVZBKnfw==
Sec-WebSocket-Version:13
Upgrade:websocket
2、服务端接收请求后主要是成针对Sec-WebSocket-Key生成相应的加密key,采用的算法是sha1算法库,生成key后,和客户端握手成功,服务器端返回内容如下:
HTTP/1.1 101 Switching Protocols
Connection:Upgrade
Server:beetle websocket server
Upgrade:WebSocket
Date:Mon, 26 Nov 2012 23:42:44 GMT
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:content-type
Sec-WebSocket-Accept:FCKgUr8c7OsDsLFeJTWrJw6WO8Q=
三、数据传输
客户端和服务器连接成功后,就可以进行通信了,通信协议格式是WebSocket格式,服务器端采用Tcp Socket方式接收数据,进行解析,协议格式如下:
第一个字节
FIN:1位,用于描述消息是否结束,如果为1则该消息为消息尾部,如果为零则还有后续数据包;
uint8_t fin = (uint8_t)msg[pos] >> 7;
RSV1,RSV2,RSV3,各1位,用于扩展定义的,如果没有扩展约定的情况则必须为0
OPCODE:4位,用于表示消息接收类型,如果接收到未知的opcode,接收端必须关闭连接。
uint8_t opcode = msg[pos] & 0x0f; 0x0表示附加数据帧 0x1表示文本数据帧 0x2表示二进制数据帧 0x3-7暂时无定义,为以后的非控制帧保留 0x8表示连接关闭 0x9表示ping 0xA表示pong 0xB-F暂时无定义,为以后的控制帧保留
第二个字节
MASK:1位,用于标识PayloadData是否经过掩码处理,客户端发出的数据帧需要进行掩码处理,所以此位是1。数据需要解码
uint8_t mask = (uint8_t)msg[pos] >> 7;
PayloadData的长度:7位,7+16位,7+64位
如果其值在0-125,则是payload的真实长度。
如果值是126,则后面2个字节形成的16位无符号整型数的值是payload的真实长度。注意,网络字节序,需要转换。
如果值是127,则后面8个字节形成的64位无符号整型数的值是payload的真实长度。注意,网络字节序,需要转换。
长度表示遵循一个原则,用最少的字节表示长度(我理解是尽量减少不必要的传输)。举例说,payload真实长度是124,在0-125之间,必须用前7位表示;不允许长度1是126或127,然后长度2是124,这样违反原则。
uint64_t payload_length_ = msg[pos] & 0x7f;
pos++;
if(payload_length_ == 126){
uint16_t length = 0;
memcpy(&length, msg + pos, 2);
pos += 2;
payload_length_ = ntohs(length);
}
else if(payload_length_ == 127){
uint32_t length = 0;
memcpy(&length, msg + pos, 4);
pos += 4;
payload_length_ = ntohl(length);
}
后面的字节就是消息体,获取消息体内如如下:
char payload_[2048];
memset(payload_, 0, sizeof(payload_));
if(mask_ != 1){
memcpy(payload_, msg + pos, payload_length_);
}
else {
for(uint i = 0; i < payload_length_; i++){
int j = i % 4;
payload_[i] = msg[pos + i] ^ masking_key_[j];
}
}
pos += payload_length_;