简易websocket讲解

websocket协议

未完待续

websocket流程

websocket通信的状态分析

enum{
	WS_HANDSHARK,
	WS_TRANSDATA,
	WS_DISCONNECT,
}
  1. 建立连接 (WS_HANDSHARK)
  2. 传输数据 (WS_TRANSDATA)
  3. 断开连接 (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 {

	}
}

建立连接

流程

  1. 客户端发送http包头
  2. 服务端接收到到http包头
  3. 从包头中获取Sec-WebSocket-Key字段(该字段由客户端随机生成)
  4. 将websocketkey字段加入GUID到后缀
  5. 执行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 ...                |
+---------------------------------------------------------------+

  1. b0–b7:操作码
  2. MASK: 是否是密文
  3. b9–b15: 该帧数据长度
  4. B2-B3 : 如果payload=126,这两个字节才存在
  5. B4-B9 : 如果payload=127, 这6个字节才存在
  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);
	}
}

发送数据

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值