前提:
本人最近做的项目,服务器端用的是C++写的,而与客户端交互用的是websocket,服务器端要想正常的使用数据,必须要对websocket协议进行解析。
解析握手协议见我上一章内容: C++实现websocket服务器握手协议
WebSocket数据格式
- FIN:表示这个数据是不是接收完毕,为1表示收到的数据是完整的,占1bit
- RSV1~3:用于扩展,通常都为0,各占1bit
- OPCODE:表示报文的类型,占4bit
- 0x00:标识一个中间数据包
- 0x01:标识一个text数据包
- 0x02:标识一个二进制数据包
- 0x03~07:保留
- 0x08:标识一个断开连接数据包
- 0x09:标识一个ping数据包
- 0x0A:标识一个pong数据包
- 0x0B~F:保留
- MASK:用于表示数据是否经常掩码处理,为1时,Masking-key即存在,占1bit
- Payload len:表示数据长度,即Payload Data的长度,当Payload len为0~125时,表示的值就是Payload Data的真实长度;当Payload len为126时,报文其后的2个字节形成的16bits无符号整型数的值是Payload Data的真实长度(网络字节序,需转换);当Payload len为127时,报文其后的8个字节形成的64bits无符号整型数的值是Payload Data的真实长度(网络字节序,需转换);
- Masking-key:掩码,当Mask为1时存在,占4字节32bit
- Payload Data:表示数据
C++对websocket协议处理
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85/** * @brief getWSFrameData 解析websocket的协议包,不能解决粘包半包问题 * @param msg 待解析的数据 * @param msgLen 待解析的数据长度 * @param outBuf 解析完成数据 * @return */ int unPackingWSFrameData(char *msg, int msgLen, std::vector<char> &outBuf) { //报文长度一定大于2字节,对于小于的,做返回处理 if(msgLen < 2) { return -3; } uint8_t opcode_ = 0; uint8_t mask_ = 0; uint8_t masking_key_[4] = {0,0,0,0}; uint64_t payload_length_ = 0; int pos = 0; //Opcode opcode_ = msg[pos] & 0x0f; pos++; //MASK mask_ = (unsigned char)msg[pos] >> 7; //Payload length 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, 8); pos += 8; payload_length_ = ntohl(length); } //Masking-key if(mask_ == 1) { for(int i = 0; i < 4; i++) { masking_key_[i] = msg[pos + i]; } pos += 4; } //取出消息数据 if (msgLen >= pos + payload_length_ ) { outBuf.clear(); if(mask_ != 1) { char* dataBegin = msg + pos; outBuf.insert(outBuf.begin(), dataBegin, dataBegin+payload_length_); } else { for(uint i = 0; i < payload_length_; i++) { int j = i % 4; outBuf.push_back(msg[pos + i] ^ masking_key_[j]); } } } else { //此时包长小于报文中记录的包长 return -2; } //断开连接类型数据包 if ((int)opcode_ == 0x8) return -1; return 0; }
以上函数即实现了对收到websocket数据的解析,返回结果为:vector<char>output;
通常会在函数外面对此进行转换为char*,方便我们使用,见下:
复制代码
1
2vector<char>output; char* out = &output[0];
当然,现在的解析还不是完美的解决方法,因为在实际的使用当中,会存在接收的包粘包,半包等等问题,而以上函数只能解决收到包正好是一个完整的包的情况;具体解决粘包半包问题,留待下次博客吧!
参考:
C++ 使用 websocket 协议
结尾:
只为记录,只为分享! 愿所写能对你有所帮助。不忘记点个赞,谢谢~
最后
以上就是醉熏小鸽子最近收集整理的关于C++实现WebSocket解析协议前提:WebSocket数据格式C++对websocket协议处理的全部内容,更多相关C++实现WebSocket解析协议前提内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复