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

news2024/11/13 15:11:09

基于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);
                else
                    conn.send_text(data);
            });

    app.loglevel(LogLevel::Debug).port(18080).multithreaded().run();

3.3 运行测试

在这里插入图片描述

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

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【BASH】回顾与知识点梳理(十七)

【BASH】回顾与知识点梳理 十七 十七. 什么是 Shell scripts17.1 干嘛学习 shell scripts自动化管理的重要依据追踪与管理系统的重要工作简单入侵检测功能连续指令单一化简易的数据处理跨平台支持与学习历程较短 17.2 第一支 script 的撰写与执行撰写第一支 script 17.3 撰写 s…

NACOS2.0本地单机版

问题 由于某些原因服务器上面的nacos临时不能使用了&#xff0c;需要开发每个人在本机搭个单机nacos进行调试开发。&#x1f611;一言难尽。 这里假设本机已经安装好Java8的环境了。 步骤 下载二进制包 直接跑到nacos的github项目页面下载就行了。 https://github.com/aliba…

Linux常用命令(一):创建文件目录

一、touch&#xff1a; 1、作用&#xff1a; 1). 改变已有文件的时间戳属性&#xff0c;修改文件时间戳时&#xff0c;用户必须的文件的属主&#xff0c;或者拥有写文件的权限 2). 创建新的空文件 2、语法&#xff1a; touch [option] 文件名 ,后面可跟多个文件名3、示例 …

企业权限管理(六)-订单详情

订单详情查询 跳转到订单详情页面orders-show.jsp <button type"button" class"btn bg-olive btn-xs" onclick"location.href${pageContext.request.contextPath}/orders/findById.do?id${orders.id}">详情</button>OrdersControl…

大数据Flink(五十九):Flink on Yarn的三种部署方式介绍以及注意

文章目录 Flink on Yarn的三种部署方式介绍以及注意 一、Pre-Job 模式部署作业

【Stable Diffusion】雨天、湿身

一、Models 1.1、Wet Clothes (Clothing Style) [LoHA] WECL SEE-THROUGH WET WET HAIR BIKINI OR SWIMSUIT UNDER CLOTHES NO BRA BRA VISIBLE THROUGH CLOTHES MISC SHIRTS MISC CLOTHES1.2、Rain 雨 Multiply Style rain style1.3、Wet T-Shirt LORA <lora:wetshirt:…

虹科方案 | 成都大运会进行时,保障大型活动无线电安全需要…

成都大运会 7月28日&#xff0c;备受关注的第31届世界大学生夏季运动会在成都正式开幕。据悉&#xff0c;这是全球首个5G加持的智慧大运会&#xff0c;也是众多成熟信息技术的综合“应用场”。使用基于5G三千兆、云网、8K超高清视频等技术&#xff0c;在比赛现场搭建多路8K摄像…

python的gui界面程序爬虫,python的gui界面怎么打开

大家好&#xff0c;小编来为大家解答以下问题&#xff0c;python的gui界面怎么打开&#xff0c;python的gui界面程序爬虫&#xff0c;今天让我们一起来看看吧&#xff01; Python支持多种图形界面的第三方库&#xff0c;包括&#xff1a; wxWidgets Qt GTK Tkinter&#xf…

PreScan 8.5.0 安装

PreScan 8.5.0 安装 prescan8.5安装教程&#xff08;详细&#xff09; Prescan8.5安装详细教程 主要参照第一篇博客进行安装&#xff0c;我将所有的东西都装到了E盘&#xff08;一共就两个盘&#xff09; 安装并用破解文件覆盖掉原文件后&#xff0c;需要配置环境变量 注意新建…

hhc.exe本地制作、手动生成chm电子书

准备几个文件 test.hhp&#xff08;配置文件&#xff09;test.hhc&#xff08;目录文件&#xff09;test.html&#xff08;点击节点右侧显示的内容&#xff09;hhc.exe去这里下载&#xff0c;链接在文章最后 test.hhp [OPTIONS] Compiled filetest.chm Contents filetest.hhc …

libuv 应用

找到了一份示例代码.根据实际情况做了修改 #include <arpa/inet.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <uv.h>#define DEFAULT_PORT 4080 #define DEFAULT_BACKLOG 128uv_loop_t…

MySQL单表查询操作(SELECT语句)

目录 步骤 1、创建表单 2、添加数据 3、显示所有职工的基本信息 4、查询所有职工所属部门的部门号&#xff0c;不显示重复的部门号 5、 求出所有职工的人数 6、 列出最高工资和最低工资 7、 列出职工的平均工资和总工资 8、 创建一个只有职工号、姓名和参加工作的新表&a…

Kafka3.0.0版本——Broker(服役新节点)示例

目录 一、服务器信息二、VMware克隆服务节点&#xff08;将虚拟机1克隆成虚拟机4 &#xff09;三、克隆后的&#xff08;192.168.136.30&#xff09;服务节点配置文件修改3.1、修改zookeeper服务配置文件3.2、修改kafka服务配置文件3.3、先启动zookeeper&#xff0c;再启动kafk…

Cesium中通过射线计算日照

Cesium中通过射线计算日照 前段时间接触到一个需求&#xff0c;需要实时的计算建筑的日照&#xff0c;通常优先通过shadow map来实现。通过shadow map可以直接获取某一时刻的光照信息&#xff0c;累积不同太阳光位置的shadow map即可得到物体表面的光照时长。 不过本人技术有限…

Pycharm如何打断点进行调试?

断点调试&#xff0c;是编写程序中一个很重要的步骤&#xff0c;有些简单的程序使用print语句就可看出问题&#xff0c;而比较复杂的程序&#xff0c;函数和变量较多的情况下&#xff0c;这时候就需要打断点了&#xff0c;更容易定位问题。 一、添加断点 在代码的行标前面&…

C++/Qt 读写文件

之前写过两篇跟文件操作相关的博客&#xff0c;有兴趣也可以看一下&#xff1a; C语言读写文件 Qt关于文件路径的处理 先讲一些关于基础文本文件和二进制文件的读写操作&#xff0c;后续将会整理C/Qt关于ini、xml、json、xlsx相关文件的读写操作。 C 相比于C语言使用FILE文…

centos7安装phpipam1.4

by:铁乐与猫 date&#xff1a;2021-5-11 安装依赖 sudo yum install epel-release sudo yum install php-mcrypt安装 Apache, MySQL, PHP (LAMP) stack packages sudo yum install httpd mariadb-server php php-cli php-gd php-common php-ldap php-pdo php-pear php-snmp …

c++11 标准模板(STL)(std::basic_fstream)(三)

定义于头文件 <fstream> template< class CharT, class Traits std::char_traits<CharT> > class basic_fstream : public std::basic_iostream<CharT, Traits> 类模板 basic_fstream 实现基于文件的流上的高层输入/输出。它将 std::basic_i…

JPA实现存储实体类型信息

本文已收录于专栏 《Java》 目录 背景介绍概念说明DiscriminatorValue 注解&#xff1a;DiscriminatorColumn 注解&#xff1a;Inheritance(strategy InheritanceType.SINGLE_TABLE) 注解&#xff1a; 实现方式父类子类执行效果 总结提升 背景介绍 在我们项目开发的过程中经常…

Node RESTful API说明

1、什么是 REST REST即表述性状态传递&#xff1b; 表述性状态转移是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是RESTful。需要注意的是&#xff0c;REST是设计风格而不是标准。 2、HTTP 方法 以下为 REST 基本架构的四个方法&#xff1a; GET - …