基于Crow的C++的WebSocket服务器

基于Crow的C++的WebSocket服务器

一、WebSocket

1.1 什么是WebSocket

WebSocket 是一种持久化的通讯协议。
很多网站为了实现推送技术,所用的技术都是轮询,这种解决方案是指由浏览器每隔一段时间向服务器发出 HTTP 请求,然后服务器返回最新的数据给客户端。这种模式有很明显的缺点,即浏览器需要不断的向服务器发出请求,然而 HTTP 请求与响应可能会包含较长的头部,其中真正有效的数据可能只是很小的一部分,所以这样会消耗很多带宽资源。

WebSocket 是一种网络传输协议,其本质是前端与服务器端建立一条TCP长连接,服务端可以随时向前端推送数据,前端也可以随时向服务端发送数据,实现了两者间双向数据实时传输。WebSocket 协议在 2011 年由 IETF 标准化为 RFC 6455,后由 RFC 7936 补充规范。WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输。

WebSocket 与 HTTP 对比如下:
在这里插入图片描述

WebSocket 的优点:

  • 1)较少的控制开销:在连接创建后,服务器和客户端之间交换数据时,用于协议控制的数据包头部相对较小;
  • 2)更强的实时性:由于协议是全双工的,所以服务器可以随时主动给客户端下发数据。相对于 HTTP 请求需要等待客户端发起请求服务端才能响应,延迟明显更少;
  • 3)保持连接状态:与 HTTP 不同的是,WebSocket 需要先创建连接,这就使得其成为一种有状态的协议,之后通信时可以省略部分状态信息;
  • 4)更好的二进制支持:WebSocket 定义了二进制帧,相对 HTTP,可以更轻松地处理二进制内容;
  • 5)可以支持扩展:WebSocket 定义了扩展,用户可以扩展协议、实现部分自定义的子协议。

1.2 协议结构

1.2.1 数据帧结构

前面提到的RFC6455中定义了数据帧的格式,如下:

在这里插入图片描述

数据帧的组成结构和其他协议类似,都是数据头+消息体(payload,直译为荷载),不过WebSocket的数据头长度是可变的,受两个因素影响:

  • 消息体长度的大小,也就是图上的Payload len: 占7或7+16或7+64bit。
  • 是否有maks key,有的话头部多4个字节。

1.2.1 数据帧格式

  • FIN: 1bit

    • 0 表示不是消息的最后一个分片
    • 1 表示是消息的最后一个分片
  • RSV1, RSV2, RSV3: 各占1bit, 一般情况下全为0, 与Websocket拓展有关, 如果出现非零的值且没有采用WebSocket拓展, 连接出错。

  • Opcode: 4bit

    • %x0: 表示本次数据传输采用了数据分片, 当前数据帧为其中一个数据分片
    • %x1: 表示这是一个文本帧
    • %x2: 表示这是一个二进制帧
    • %x3-7: 保留的操作代码, 用于后续定义的非控制帧
    • %x8: 表示连接断开
    • %x9: 表示这是一个心跳请求(ping)
    • %xA: 表示这是一个心跳响应(pong)
    • %xB-F: 保留的操作代码, 用于后续定义的非控制帧
  • Mask: 占1bit

    • 0表示不对数据载荷进行掩码异或操作
    • 1表示对数据载荷进行掩码异或操作
  • Payload len: 占7或7+16或7+64bit

    • 0~125: 数据长度等于该值
    • 126: 后续的2个字节代表一个16位的无符号整数, 值为数据的长度
    • 127: 后续的8个字节代表一个64位的无符号整数, 值为数据的长度
  • Masking-key: 占0或4bytes;只有客户端给服务器端发送数据时才会有masking key,服务器端给客户端发送数据不需要masking key

    • 1: 携带了4字节的Masking-key
    • 0: 没有Masking-key
  • payload data: 消息体

1.2.2 掩码算法

结构体中有一个Masking-key,这是一个掩码字段,它是一个由客户端随机选择的 32 位的值。掩码值必须是不可被预测的。因此,掩码必须来自强大的熵源(entropy),并且给定的掩码不能很容易的预测到后续帧,掩码的不可预测性对于预防恶意应用的作者在网上暴露相关的字节数据至关重要。

掩码只影响头的长度,不影响消息体,对数据进行掩码操作和对数据进行反掩码操作所涉及的步骤是相同的。

掩码、反掩码操作都采用如下算法:

j = i MOD 4
transformed-octet-i = original-octet-i XOR masking-key-octet-j

其中:

  • 1)original-octet-i:为原始数据的第 i 字节;
  • 2)transformed-octet-i:为转换后的数据的第 i 字节;
  • 3)masking-key-octet-j:为 mask key 第 j 字节。

算法是完全公开的,运算起来也不复杂。所以数据掩码的作用是增强协议的安全性。而不是为了保护数据本身,应该主要还是为了防止早期版本的协议中存在的代理缓存污染攻击等问题。

1.3 与WebSocket类似的协议

1.3.1 AJAX Polling:

客户端使用普通的http方式向服务器端请求网页,同时执行轮询脚本,定期循环的向服务器发送请求(例如每5秒发送一次请求),获取信息
服务器对每次请求作出响应,并返回相应信息,就像正常的http请求一样;
缺点:轮询耗费资源

1.3.2 AJAX Long-Polling:

与普通的polling相比区别就是异步等待;
客户端使用普通的http方式向服务器端请求网页,同时执行轮询脚本,向服务器发送数据、请求信息;
但是服务器并不是立即就对客户端的请求作出响应,而是等待有效的更新;
当信息是有效的更新时,服务器才会把数据推送给客户端;
当客户端接收到服务器的通知时,立即会发送一个新的请求,进入到下一次的轮询;
缺点:无更新时发送请求浪费资源

1.3.3 Server Sent Events (SSE) / EventSource:

客户端使用普通的http方式向服务器端请求网页,同时网页与服务器之间建立了一个连接;
当服务器端有更新时,会发送一个事件到客户端;
服务器无更新但客户端有请求时,仍使用HTTP模式进行请求与应答;
优点是如果已有的代码是HTTP请求,那么服务器可以不影响现有代码的情况下支持SSE;
缺点是半双工,客户端无法向服务器发送请求,并且部分浏览器不支持。

1.3.4 Comet:

Comet是一种用于web的推送技术,能使服务器实时地将更新的信息传送到客户端,而无须客户端发出请求,目前有两种实现方式,长轮询和iframe流。

  • 长轮询
    长轮询是在打开一条连接以后保持,等待服务器推送来数据再关闭的方式。
  • iframe流
    iframe流方式是在页面中插入一个隐藏的iframe,利用其src属性在服务器和客户端之间创建一条长链接,服务器向iframe传输数据(通常是HTML,内有负责插入信息的javascript),来实时更新页面。
    iframe流方式的优点是浏览器兼容好,Google公司在一些产品中使用了iframe流,如Google Talk。

1.3.5 WebRTC

WebRTC 是一种实时媒体传输技术,最初是一个开源项目,主要目标是为浏览器和移动应用程序提供建立连接的方法。一个连接是通过指示信号和同步信号建立的,这个过程被称为信令。为了在两个设备之间建立 WebRTC 连接,需要一个信令服务器。它是一个中间件,除了承担建立连接的主要功能外,还最大程度上降低了有价值的信息和机密数据泄露的风险。
WebRTC的延迟很低,很适合用于大数据量的传输;并且因为支持自定义协议,所以安全性可控;缺点是只有部分浏览器支持,以及需要中间件等。

二、CroW

2.1 什么是Crow

Crow是一个用C++编写的WebSocket框架,旨在提供简单易用的API和高性能。它最初是由Mozilla开发的,现在已经成为了一个独立的开源项目。它使用了类似于Python的Flask的路由,这使得它易于使用,同时其处理速度也很快。

2.2 优点以及缺点

2.2.1 优点

简单易用:Crow提供了简单易用的API,可以快速构建WebSocket服务器和客户端应用程序。
高性能:Crow使用了Asio库来处理网络I/O操作(旧版使用Boost.asio,目前已更新为独立版asio),可以实现高效的并发处理。此外,它还支持SSL/TLS加密,可以保证通信的安全性和可靠性。
可扩展性:Crow提供了插件机制,可以方便地扩展其功能。例如,可以通过编写自定义插件来实现自定义的消息处理逻辑。
跨平台:Crow可以在多种平台上运行,包括Windows、Linux和macOS等操作系统。

2.2.2 缺点

文档不够完善:Crow的文档很清晰简洁,相比于其他一些WebSocket框架来说,它的文档还有待进一步完善。
缺乏实时消息队列支持:Crow目前还不支持实时消息队列功能,如果需要实现类似消息队列的功能,需要自己编写相关的代码。
不支持多路复用:Crow目前只支持单个TCP连接,如果需要同时处理多个客户端请求,需要为每个客户端创建一个新的线程或进程。
不支持HTTPS:虽然Crow支持SSL/TLS加密,但是不支持HTTPS协议。如果需要通过HTTPS协议进行通信,需要自己实现相关的加密算法。
不适合大规模应用:由于Crow的设计初衷是用于小型到中型的应用场景,因此在面对大规模应用时可能会出现性能瓶颈等问题。

2.3 编译安装

在安装Crow之前需要先安装ASIO,要求1.22.0以上的版本;

然后下载、MAKE、install:

git clone https://github.com/CrowCpp/Crow.git
mkdir build
cd build
cmake .. -DCROW_BUILD_EXAMPLES=OFF -DCROW_BUILD_TESTS=OFF
make install

之后能看到如下目录:
在这里插入图片描述
其中include里的就是所有的源码,平时用的时候只需要包含include/crow.h即可

三、基于Crow的C++服务器与客户端示例

3.1 客户端

客户端我是用HTML+JS那一套,Crow也可以写C++客户端;
JS里面使用WebSocket可以直接使用WebSocket对象,这个类只有两个函数

var wSocket = new WebSocket("ws://localhost:18080/ws");
wSocket.close([code[, reason]]) // 关闭当前链接
wSocket.send(data) // 发送数据

写一个html,在里面加一个按钮,点击然后调用send发送数据即可;
具体可参考: https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket

3.2 服务器

先定义Crow::app对象,然后绑定ws路由,再监听指定端口即可,

    CROW_WEBSOCKET_ROUTE(app, "/ws").onopen([&](crow::websocket::connection& conn) {CROW_LOG_INFO << "new websocket connection from " << conn.get_remote_ip();}).onclose([&](crow::websocket::connection& conn, const std::string& reason) {CROW_LOG_INFO << "websocket connection closed: " << reason;}).onmessage([&](crow::websocket::connection& conn, const std::string& data, bool is_binary) {CROW_LOG_INFO << "Recv message:" << data;if (is_binary)conn.send_binary(data);elseconn.send_text(data);});app.loglevel(LogLevel::Debug).port(18080).multithreaded().run();

3.3 运行测试

在这里插入图片描述

还可以使用测试网站:http://www.websocket-test.com/ (这个网站是我看到某个文章上推的,安全性未知)

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/60690.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

安卓:实现复制粘贴功能

目录 一、介绍 &#xff08;一&#xff09;ClipboardManager介绍 1、ClipboardManager常用方法&#xff1a; 2、获取 ClipboardManager实例 &#xff08;二&#xff09;、ClipData介绍 1、创建ClipData对象&#xff1a; 2、获取ClipData的信息&#xff1a; 3、ClipData…

【代码】表格封装 + 高级查询 + 搜索 +分页器 (极简)

一、标题 查询条件按钮&#xff08;Header&#xff09; <!-- Header 标题搜索栏 --> <template><div><div class"header"><div class"h-left"><div class"title"><div class"desc-test">…

基于kettle实现pg数据定时转存mongodb

mogodb 待创建 基于kettle实现pg数据定时转存mongodb_kettle 实时迁移 mongodb_呆呆的私房菜的博客-CSDN博客

状态模式(C++)

定义 允许一个对象在其内部状态改变时改变它的行为。从而使对象看起来似乎修改了其行为。 应用场景 在软件构建过程中&#xff0c;某些对象的状态如果改变&#xff0c;其行为也会随之&#xff0c;而发生变化&#xff0c;比如文档处于只读状态&#xff0c;其支持的行为和读写…

【JVM】 垃圾回收篇——自问自答(1)

Q什么是垃圾&#xff1a; 运行程序中&#xff0c;没用任何指针指向的对象。 Q为什么需要垃圾回收&#xff1f; 内存只分配&#xff0c;不整理回收&#xff0c;迟早会被消耗完。 内存碎片的整理&#xff0c;为新对象腾出空间 没有GC程序无法正常进行。 Q 哪些区域有GC&#…

esp8266使用arduinoJson与tft_espi库发生冲突解决方法

esp8266使用arduinoJson与tft_espi库发生冲突解决方法 arduinoJson与tft_espi库发生冲突解决方法下载arduinoJson5.0版本的&#xff0c;不要用最新版本 示范代码&#xff1a; // Copyright Benoit Blanchon 2014 // MIT License // // Arduino JSON library // https://git…

springboot mongo 使用

nosql对我来说&#xff0c;就是用它的变动列&#xff0c;如果列是固定的&#xff0c;我为什么不用mysql这种关系型数据库呢&#xff1f; 所以&#xff0c;现在网上搜出来的大部分&#xff0c;用实体类去接的做法&#xff0c;并不适合我的需求。 所以&#xff0c;整理记录一下…

【资料分享】全志科技T507-H工业核心板规格书

1 核心板简介 创龙科技SOM-TLT507是一款基于全志科技T507-H处理器设计的4核ARM Cortex-A53全国产工业核心板&#xff0c;主频高达1.416GHz。核心板CPU、ROM、RAM、电源、晶振等所有元器件均采用国产工业级方案&#xff0c;国产化率100%。 核心板通过邮票孔连接方式引出MIPI C…

Winform中DatagridView 表头实现一个加上一个checkBox,实现全选选项功能

实现效果 点击checkBox1或者直接在第一列列表头点击即可实现 代码实现 我的datagridview叫dgv 我在datagridview已经默认添加了一个DataGridViewCheckBoxColumn&#xff0c;勾选时value为1&#xff0c;不勾选时value为0 第一种通过可视化拖动一个checkBox来实现 拖动组…

IC岗位详解| 高薪模拟版图工程师需要掌握哪些技能?

IC模拟版图设计在IC行业中是门槛相对较低的一个岗位&#xff0c;其他岗位大都要求是科班毕业&#xff0c;或者是硕士以上学历&#xff0c;IC模拟版图设计本科生也很好入门&#xff0c;对于基础差的同学这是非常好的一个入门机会。 模拟版图工程师介绍 模拟版图设计工程师为专…

爬虫如何应对网站的反爬机制?如何查找user-agent对应的值

import requestsurl https://movie.douban.com/top250 response requests.get(url) # 查看结果 print(response)在requests使用一文中我们有讲到&#xff0c;当状态码不是200时表示爬虫不可用&#xff0c;也就是说我们获取不到网页源代码。但是我们还是可以挣扎一下&#xff…

以商业大数据技术助力数据合规流通体系建立,合合信息参编《数据经纪从业人员评价规范》团标

经国务院批准&#xff0c;由北京市人民政府、国家发展和改革委员会、工业和信息化部、商务部、国家互联网信息办公室、中国科学技术协会共同主办的2023 全球数字经济大会于近期隆重召开。由数交数据经纪&#xff08;深圳&#xff09;有限公司为主要发起单位&#xff0c;合合信息…