C++实现websocket协议通讯

  在获取服务器的数据时,我们传统的做法是通过前端进行请求服务器返回数据。这样如果我们要获取的数据不是连续的,或者服务器想想前端推送数据只能通过ajax等轮询请求了。html5以后我们可以通过websocket和服务器进行通信,前端和服务连接后就可以进行双工连接了。服务器有数据就能实时的给前端推送,而不需要我定时的去请求。

  websocket简单来说就是先前端向服务器发送http的请求,服务端通过前端请求的http的key值进过sha1和base64加密返回给前端,这一过程称为“握手”,如果验证成功就能进行websocket通讯了。握手成功后前端和后端通讯都要符合webscoket的协议才能通讯。关于websocket的协议大家可以网上查找,这里不作讨论。

  最近在要实现一个后端将设配读到数据主动发前端的功能,网上查找了一些大佬写好程序进行参考更改。这里谢谢他们,希望没有侵权。下面是主要代码。

  

 1 #ifndef __WebSocketProtocol_H__
 2 #define __WebSocketProtocol_H__
 3
 4 #include <string>
 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 <iostream>
  3 #include <sstream>
  4 #include <string.h>
  5 #include <arpa/inet.h>
  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<const unsigned char*>(message_digest), 20);
 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<uint8_t>(frameData[0] & 0x0f);
129     if (opcode == WS_TEXT_FRAME)
130     {
131         // 处理utf-8编码的文本帧
132         payloadLength = static_cast<uint16_t>(frameData[1] & 0x7f);
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<uint8_t>(0x80 | frameType);
198
199     // 填充数据长度
200     if (messageLength <= 0x7d)
201     {
202         frameHeader[1] = static_cast<uint8_t>(messageLength);
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 }

参考资料:http://www.cnblogs.com/jice1990/p/5435419.html

    http://blog.csdn.net/grafx/article/details/54234518#

项目下载

时间: 2024-11-29 09:06:08

C++实现websocket协议通讯的相关文章

Websocket 协议解析

WebSocket protocol 是HTML5一种新的协议.它是实现了浏览器与服务器全双工通信(full-duplex). 现 很多网站为了实现即时通讯,所用的技术都是轮询(polling).轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP request,然后由服务器返回最新的数据给客服端的浏览器.这种传统的HTTP request 的模式带来很明显的缺点 – 浏览器需要不断的向服务器发出请求,然而HTTP request 的header是非常长的,里面包含的数据可能只是

Websocket协议的学习、调研和实现

1. websocket是什么 Websocket是html5提出的一个协议规范,参考rfc6455. websocket约定了一个通信的规范,通过一个握手的机制,客户端(浏览器)和服务器(webserver)之间能建立一个类似tcp的连接,从而方便c-s之间的通信.在websocket出现之前,web交互一般是基于http协议的短连接或者长连接. WebSocket是为解决客户端与服务端实时通信而产生的技术.websocket协议本质上是一个基于tcp的协议,是先通过HTTP/HTTPS协议发

(转)服务端使用c++实现websocket协议解析及通信

转自:http://blog.csdn.net/grafx/article/details/54234518 WebSocket 设计出来的目的就是要使客户端浏览器具备像 C/S 架构下桌面系统的实时通讯能力. 浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据.因为 WebSocket 连接本质上就是一个 TCP 连接,所以在数据传输的稳定性和数据传输量的大小方面,和轮询以及 Comet 技术比

用node实现websocket协议

协议 WebSocket是一种基于TCP之上的客户端与服务器全双工通讯的协议,它在HTML5中被定义,也是新一代webapp的基础规范之一. 它突破了早先的AJAX的限制,关键在于实时性,服务器可以主动推送内容 到客户端!可能的应用有:多人在线游戏,即时聊天,实时监控,远程桌面,新闻服务器等等. 对于我自己,当前最想尝试的是canvas+websocket组合起来能做什么. 实现 由于握手的过程是一个标准的HTTP请求,因此 websocket 的实现有两种选择:1)TCP上实现: 2) 现有H

基于构建实时WEb应用的HTML5 WebSocket协议&lt;一&gt;

前言 作为下一代的 Web 标准,HTML5 拥有许多引人注目的新特性,如 Canvas.本地存储.多媒体编程接口.WebSocket 等等.这其中有"Web 的 TCP "之称的 WebSocket格外吸引开发人员的注意.WebSocket 的出现使得浏览器提供对 Socket 的支持成为可能,从而在浏览器和服务器之间提供了一个基于 TCP 连接的双向通道.WebSocket是html5新增加的一种通信协议,目前流行的浏览器都支持这个协议,Web 开发人员可以非常方便地使用 WebS

基于构建实时WEb应用的HTML5 WebSocket协议&lt;二&gt;

前面说了那么多的理论,我们来看下代码学习. WebSocketAPI简介 首先看一段简单的javascript代码,该代码调用了WebSockets的API. var ws = new WebSocket("ws://echo.websocket.org"); ws.onopen = function(){ws.send("Test!"); }; ws.onmessage = function(evt){console.log(evt.data);ws.close(

TCP,HTTP,socket,WEBSOCKET协议

一.TCP协议 1.传输层通信协议 2.面向连接的,可靠的,基于字节流的 3.建立链接需要三次握手 4.TCP可以保证数据无丢失,数据无失序,数据无错误,数据无重复到达. 二.Http协议 1.一个应用层协议 2.Header-Body组成 3.比TCP高级 4.短链接,无状态 5.http请求步骤 ①.客户机通过TCP/IP协议建立到服务器的TCP连接. ②.客户端向服务器发送http请求. ③.服务器向客户机发送Http协议应答包. ④.断开链接,客户端渲染html文档. 三.socket协

WebSocket 协议

1. WebSocket 协议开发. WebSocket 是 HTML5 开始提供的一种浏览器与服务器间进行全双工通讯的网络技术,WebSocket通信协议于2011年被IETF定为标准 RFC6455 , WebSocket API 被W3C定为标准. 在 WebSocket API中,浏览器和服务器只需要做一个握手的动作,然后浏览器和服务器之间就形成了一条快熟通道,两者就可以直接互相传送数据了,WebSocket基于TCP双向全双工进行消息传递,在同一时刻,既可以发送消息,也可以接受消息,相

WebSocket协议:5分钟从入门到精通

一.内容概览 WebSocket的出现,使得浏览器具备了实时双向通信的能力.本文由浅入深,介绍了WebSocket如何建立连接.交换数据的细节,以及数据帧的格式.此外,还简要介绍了针对WebSocket的安全攻击,以及协议是如何抵御类似攻击的. 二.什么是WebSocket HTML5开始提供的一种浏览器与服务器进行全双工通讯的网络技术,属于应用层协议.它基于TCP传输协议,并复用HTTP的握手通道. 对大部分web开发者来说,上面这段描述有点枯燥,其实只要记住几点: WebSocket可以在浏