websocket协议
未完待续
websocket流程
websocket通信的状态分析
enum{
WS_HANDSHARK,
WS_TRANSDATA,
WS_DISCONNECT,
}
- 建立连接 (WS_HANDSHARK)
- 传输数据 (WS_TRANSDATA)
- 断开连接 (WS_DISCONNECT)
int websocket_request(struct ntyevent *ev){
if(ev->status==WS_HANDSHARK){
handshark(ev);
ev->status = WS_TRANSDATA;
} else if (ev->status==WS_TRANSDATA){
transmission(ev);
} else {
}
}
建立连接
流程
- 客户端发送http包头
- 服务端接收到到http包头
- 从包头中获取Sec-WebSocket-Key字段(该字段由客户端随机生成)
- 将websocketkey字段加入GUID到后缀
- 执行sha1摘要
拆解shark包
int readline(char *allbuf, int idx, char *linebuf) {
int len = strlen(allbuf);
for(;idx < len;idx ++) {
if (allbuf[idx] == '\r' && allbuf[idx+1] == '\n') {
return idx+2;
} else {
*(linebuf++) = allbuf[idx];
}
}
return -1;
}
int handshark(struct ntyevent *ev){
char buffer[1024], sha1_value[32];
int idx = 0;
do {
idx = readline(ev->buffer, idx, buffer);
if(strstr(buffer, "Sec-WebSocket-Key")){
strcat(buffer, GUID);
// strlen("Sec-WebSocket-Key: ") = 19
SHA1(buffer + 19, strlen(buffer)-19, sha1_value);
//sha1摘要结果是20字节 ,我这人比较吝啬,buffer在这里复用了
base64_encode(sha1_value, 20, buffer);
ev->length = sprintf(ev->buffer, "HTTP/1.1 101 Switching Protocols\r\n"
"Upgrade: websocket\r\n"
"Connection: Upgrade\r\n"
"Sec-WebSocket-Accept: %s\r\n\r\n", buffer);
printf("ws response : %s\n", ev->buffer);
break;
}
}while((ev->buffer[idx] != '\r' || ev->buffer[idx+1] != '\n') && idx != -1 );
}
return 0;
接收数据
协议
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 ... |
+---------------------------------------------------------------+
- b0–b7:操作码
- MASK: 是否是密文
- b9–b15: 该帧数据长度
- B2-B3 : 如果payload=126,这两个字节才存在
- B4-B9 : 如果payload=127, 这6个字节才存在
- B10-B13 一定存在,再MASK为1时侯,其中数据生效
解码
void umask(char *payload, int length, char *mask_key) {
int i = 0;
for (i = 0;i < length;i ++) {
payload[i] ^= mask_key[i%4];
}
}
封装websocket的head包
typedef struct {
uint8_t opcode : 4;
uint8_t rsv3 : 1;
uint8_t rsv2 : 1;
uint8_t rsv1 : 1;
uint8_t fin : 1;
uint8_t p1_len : 7;
uint8_t mask : 1;
}ws_ophdr;
typedef struct {
unsigned short payload_length;
char mask_key[4];
} ws_head_126;
typedef struct {
long long payload_length;
char mask_key[4];
} ws_head_127;
拆包
int transmission(struct ntyevent *ev) {
//ev->buffer; ev->length
ws_ophdr*hdr = (ws_ophdr*)ev->buffer;
printf("length: %d\n", hdr->pl_len);
if (hdr->pl_len < 126) { //
//4是4个字节的Masking-key
unsigned char *payload = ev->buffer + sizeof(ws_ophdr) + 4;
if (hdr->mask) { // mask set 1
umask(payload, hdr->pl_len, ev->buffer+2);
}
printf("payload : %s\n", payload);
} else if (hdr->pl_len == 126) {
ws_head_126 *hdr126 = ev->buffer + sizeof(ws_ophdr);
} else {
ws_head_127 *hdr127 = ev->buffer + sizeof(ws_ophdr);
}
}