摘要:本文主要向大家介绍了 C/C++知识点之C++实现websocket协议通讯,通过具体的内容向大家展示,希望对大家学习C/C++知识点有所帮助。
本文主要向大家介绍了 C/C++知识点之C++实现websocket协议通讯,通过具体的内容向大家展示,希望对大家学习C/C++知识点有所帮助。
在获取服务器的数据时,我们传统的做法是通过前端进行请求服务器返回数据。这样如果我们要获取的数据不是连续的,或者服务器想想前端推送数据只能通过ajax等轮询请求了。html5以后我们可以通过websocket和服务器进行通信,前端和服务连接后就可以进行双工连接了。服务器有数据就能实时的给前端推送,而不需要我定时的去请求。 websocket简单来说就是先前端向服务器发送http的请求,服务端通过前端请求的http的key值进过sha1和base64加密返回给前端,这一过程称为“握手”,如果验证成功就能进行websocket通讯了。握手成功后前端和后端通讯都要符合webscoket的协议才能通讯。关于websocket的协议大家可以网上查找,这里不作讨论。
最近在要实现一个后端将设配读到数据主动发前端的功能,网上查找了一些大佬写好程序进行参考更改。这里谢谢他们,希望没有侵权。下面是主要代码。
1 #ifndef __WebSocketProtocol_H__
2 #define __WebSocketProtocol_H__
3
4 #include
5
6 using std::string;
7
8 class CWebSocketProtocol
9 {
10 public:
11 enum WS_Status
12 {
13 WS_STATUS_CONNECT = 0,
14 WS_STATUS_UNCONNECT = 1,
15 };
16
17 enum WS_FrameType
18 {
19 WS_EMPTY_FRAME = 0xF0,
20 WS_ERROR_FRAME = 0xF1,
21 WS_TEXT_FRAME = 0x01,
22 WS_BINARY_FRAME = 0x02,
23 WS_PING_FRAME = 0x09,
24 WS_PONG_FRAME = 0x0A,
25 WS_OPENING_FRAME = 0xF3,
26 WS_CLOSING_FRAME = 0x08
27 };
28
29 static CWebSocketProtocol * getInstance();
30
31 int getResponseHttp(string &request, string &response);
32 int wsDecodeFrame(string inFrame, string &outMessage); //解码帧
33 int wsEncodeFrame(string inMessage, string &outFrame, enum WS_FrameType frameType); //编码帧打包
34
35 private:
36 CWebSocketProtocol();
37 ~CWebSocketProtocol();
38
39 class CGrabo
40 {
41 public:
42 ~CGrabo()
43 {
44 if (m_inst != 0)
45 {
46 delete m_inst;
47 m_inst = 0;
48 }
49 }
50 };
51
52 static CGrabo m_grabo;
53 static CWebSocketProtocol * m_inst;
54 };
55
56 #endif
1 #include "WebSocketProtocol.h"
2 #include
3 #include
4 #include
5 #include
6 #include "sha1.h"
7 #include "base64.h"
8
9 const char * MAGIC_KEY = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
10
11 CWebSocketProtocol::CGrabo CWebSocketProtocol::m_grabo;
12 CWebSocketProtocol * CWebSocketProtocol::m_inst = 0;
13
14 CWebSocketProtocol::CWebSocketProtocol()
15 {
16 }
17
18
19 CWebSocketProtocol::~CWebSocketProtocol()
20 {
21 }
22
23
24
25 CWebSocketProtocol * CWebSocketProtocol::getInstance()
26 {
27 if (m_inst != 0)
28 {
29 m_inst = new CWebSocketProtocol;
30 }
31
32 return m_inst;
33 }
34
35 int CWebSocketProtocol::getResponseHttp(string &request, string &response)
36 {
37 // 解析http请求头信息
38 int ret = WS_STATUS_UNCONNECT;
39 std::istringstream stream(request.c_str());
40 std::string reqType;
41 std::getline(stream, reqType);
42 if (reqType.substr(0, 4) != "GET ")
43 {
44 return ret;
45 }
46
47 std::string header;
48 std::string::size_type pos = 0;
49 std::string websocketKey;
50 while (std::getline(stream, header) && header != "\r")
51 {
52 header.erase(header.end() - 1);
53 pos = header.find(": ", 0);
54 if (pos != std::string::npos)
55 {
56 std::string key = header.substr(0, pos);
57 std::string value = header.substr(pos + 2);
58 if (key == "Sec-WebSocket-Key")
59 {
60 ret = WS_STATUS_CONNECT;
61 websocketKey = value;
62 break;
63 }
64 }
65 }
66
67 if (ret != WS_STATUS_CONNECT)
68 {
69 return ret;
70 }
71
72 // 填充http响应头信息
73 response = "HTTP/1.1 101 Switching Protocols\r\n";
74 response += "Connection: upgrade\r\n";
75 response += "Sec-WebSocket-Accept: ";
76
77 std::string serverKey = websocketKey + MAGIC_KEY;
78
79 SHA1 sha;
80 unsigned int message_digest[5];
81 sha.Reset();
82 sha << serverKey.c_str();
83
84 sha.Result(message_digest);
85 for (int i = 0; i < 5; i++) {
86 message_digest[i] = htonl(message_digest[i]);
87 }
88 serverKey = base64_encode(reinterpret_cast
89 response += serverKey;
90 response += "\r\n";
91 response += "Upgrade: websocket\r\n\r\n";
92
93 return ret;
94 }
95
96 int CWebSocketProtocol::wsDecodeFrame(string inFrame, string &outMessage)
97 {
98 int ret = WS_OPENING_FRAME;
99 const char *frameData = inFrame.c_str();
100 const int frameLength = inFrame.size();
101 if (frameLength < 2)
102 {
103 ret = WS_ERROR_FRAME;
104 }
105
106 // 检查扩展位并忽略
107 if ((frameData[0] & 0x70) != 0x0)
108 {
109 ret = WS_ERROR_FRAME;
110 }
111
112 // fin位: 为1表示已接收完整报文, 为0表示继续监听后续报文
113 ret = (frameData[0] & 0x80);
114 if ((frameData[0] & 0x80) != 0x80)
115 {
116 ret = WS_ERROR_FRAME;
117 }
118
119 // mask位, 为1表示数据被加密
120 if ((frameData[1] & 0x80) != 0x80)
121 {
122 ret = WS_ERROR_FRAME;
123 }
124
125 // 操作码
126 uint16_t payloadLength = 0;
127 uint8_t payloadFieldExtraBytes = 0;
128 uint8_t opcode = static_cast
129 if (opcode == WS_TEXT_FRAME)
130 {
131 // 处理utf-8编码的文本帧
132 payloadLength = static_cast
133 if (payloadLength == 0x7e)
134 {
135 uint16_t payloadLength16b = 0;
136 payloadFieldExtraBytes = 2;
137 memcpy(&payloadLength16b, &frameData[2], payloadFieldExtraBytes);
138 payloadLength = ntohs(payloadLength16b);
139 }
140 else if (payloadLength == 0x7f)
141 {
142 // 数据过长,暂不支持
143 ret = WS_ERROR_FRAME;
144 }
145 }
146 else if (opcode == WS_BINARY_FRAME || opcode == WS_PING_FRAME || opcode == WS_PONG_FRAME)
147 {
148 // 二进制/ping/pong帧暂不处理
149 }
150 else if (opcode == WS_CLOSING_FRAME)
151 {
152 ret = WS_CLOSING_FRAME;
153 }
154 else
155 {
156 ret = WS_ERROR_FRAME;
157 }
158
159 // 数据解码
160 if ((ret != WS_ERROR_FRAME) && (payloadLength > 0))
161 {
162 // header: 2字节, masking key: 4字节
163 const char *maskingKey = &frameData[2 + payloadFieldExtraBytes];
164 char *payloadData = new char[payloadLength + 1];
165 memset(payloadData, 0, payloadLength + 1);
166 memcpy(payloadData, &frameData[2 + payloadFieldExtraBytes + 4], payloadLength);
167 for (int i = 0; i < payloadLength; i++)
168 {
169 payloadData[i] = payloadData[i] ^ maskingKey[i % 4];
170 }
171
172 outMessage = payloadData;
173 delete[] payloadData;
174 }
175
176 return ret;
177 }
178
179 int CWebSocketProtocol::wsEncodeFrame(string inMessage, string &outFrame, enum WS_FrameType frameType)
180 {
181 int ret = WS_EMPTY_FRAME;
182 const uint32_t messageLength = inMessage.size();
183 if (messageLength > 32767)
184 {
185 // 暂不支持这么长的数据
186 std::cout << "暂不支持这么长的数据" << std::endl;
187
188 return WS_ERROR_FRAME;
189 }
190
191 uint8_t payloadFieldExtraBytes = (messageLength <= 0x7d) ? 0 : 2;
192 // header: 2字节, mask位设置为0(不加密), 则后面的masking key无须填写, 省略4字节
193 uint8_t frameHeaderSize = 2 + payloadFieldExtraBytes;
194 uint8_t *frameHeader = new uint8_t[frameHeaderSize];
195 memset(frameHeader, 0, frameHeaderSize);
196 // fin位为1, 扩展位为0, 操作位为frameType
197 frameHeader[0] = static_cast
198
199 // 填充数据长度
200 if (messageLength <= 0x7d)
201 {
202 frameHeader[1] = static_cast
203 }
204 else
205 {
206 frameHeader[1] = 0x7e;
207 uint16_t len = htons(messageLength);
208 memcpy(&frameHeader[2], &len, payloadFieldExtraBytes);
209 }
210
211 // 填充数据
212 uint32_t frameSize = frameHeaderSize + messageLength;
213 char *frame = new char[frameSize + 1];
214 memcpy(frame, frameHeader, frameHeaderSize);
215 memcpy(frame + frameHeaderSize, inMessage.c_str(), messageLength);
216 frame[frameSize] = ‘\0‘;
217 outFrame = frame;
218
219 delete[] frame;
220 delete[] frameHeader;
221 return ret;
222 }
本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标编程语言C/C+频道!
您输入的评论内容中包含违禁敏感词
我知道了
请输入正确的手机号码
请输入正确的验证码
您今天的短信下发次数太多了,明天再试试吧!
我们会在第一时间安排职业规划师联系您!
您也可以联系我们的职业规划师咨询:
版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
沪公网安备 31011502005948号