websocketpp 安装及使用

news2025/5/13 19:31:04

介绍

WebSocket 是从 HTML5 开始支持的一种网页端和服务端保持长连接的消息推送机制。
  • 传统的 web 程序都是属于 "一问一答" 的形式,即客户端给服务器发送了一个 HTTP 请求,服务器给客户端返回一个 HTTP 响应。这种情况下服务器是属于被动的一方,如果客户端不主动发起请求服务器就无法主动给客户端响应。
  • 像网页即时聊天这样的程序都是非常依赖 "消息推送" 的,即需要服务器主动推动消息到客户端。如果只是使用原生的 HTTP 协议,要想实现消息推送一般需要通过 "轮询" 的方式实现, 而轮询的成本比较高并且也不能及时的获取到消息的响应。
基于上述两个问题, 就产生了 WebSocket 协议,旨在实现客户端与服务器之间的 全双工、持久化通信 。WebSocket 更接近于 TCP 这种级别的通信方式,一旦连接建立完成客户端或者服务器都可以主动的向对方发送数据

与 HTTP 对比

特性WebSocketHTTP
连接方式持久化长连接短连接(请求-响应)
通信模式全双工半双工(客户端发起)
头部开销小(帧格式)大(每次携带完整头)
适用场景实时交互静态资源获取

核心特性

  1. 全双工通信:客户端和服务器可以同时双向发送数据,无需等待请求-响应周期。

  2. 低延迟:建立连接后,数据可以即时传输,无需重复建立连接(HTTP 每次请求需握手)。

  3. 轻量级协议:数据帧头部开销小(最小仅 2 字节),适合高频通信。

  4. 基于 TCP:工作在 OSI 模型的传输层之上,依赖 TCP 的可靠性。

原理解析

WebSocket 协议本质上是一个基于 TCP 的协议。为了建立一个 WebSocket 连接,客户端浏览器首先要向服务器发起一个 HTTP 请求,这个请求和通常的 HTTP 请求不同,包含了一些附加头信息,通过这个附加头信息完成握手过程并升级协议的过程。
  • HTTP 升级请求(客户端发起)

客户端发送一个包含 Upgrade: websocket 头的 HTTP 请求,其中 Sec-WebSocket-Key 是随机生成的 Base64 字符串,用于安全校验:

GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

  • 服务器响应切换协议

服务器返回 HTTP 101 Switching Protocols 表示协议升级成功,其中 Sec-WebSocket-Accept 是客户端 Key 与固定 GUID 拼接后通过 SHA-1 哈希生成的,用于验证握手合法性:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

  • 连接建立

此后,通信转为 WebSocket 协议,数据以帧(Frame)形式传输。

数据帧格式

WebSocket 数据帧包含以下关键字段(二进制格式):

报文字段比较多,我们重点关注这几个字段 :
  • FIN: WebSocket 传输数据以消息为概念单位,一个消息有可能由一个或多个帧组成,FIN 字段为 1 表示末尾帧。
  • RSV1~3:保留字段,只在扩展时使用,若未启用扩展则应置 1,若收到不全为 0 的数据帧,且未协商扩展则立即终止连接。
  • opcode: 标志当前数据帧的类型
  1. 0x0: 表示这是个延续帧,当 opcode 0 表示本次数据传输采用了数据分片,当前收到的帧为其中一个分片
  2. 0x1: 表示这是文本帧
  3. 0x2: 表示这是二进制帧
  4. 0x3-0x7: 保留,暂未使用
  5. 0x8: 表示连接断开
  6. 0x9: 表示 ping
  7. 0xa: 表示 pong
  8. 0xb-0xf: 保留,暂未使用
  • mask:表示 Payload 数据是否被编码,若为 1 则必有 Mask-Key,用于解码 Payload 数据。仅客户端发送给服务端的消息需要设置。
  • Payload length:数据载荷的长度,单位是字节, 有可能为 7 位、7+16 位、7+64
  • 位。假设 Payload length = x:
  1. x 0~126:数据的长度为 x 字节
  2. x 126:后续 2 个字节代表一个 16 位的无符号整数,该无符号整数的值为数据的长度
  3. x 127:后续 8 个字节代表一个 64 位的无符号整数(最高位为 0),该无符号整数的值为数据的长度
  • Mask-Key:当 mask 1 时存在,长度为 4 字节,解码规则: DECODED[i] = ENCODED[i] ^ MASK[i % 4]
  • Payload data: 报文携带的载荷数据

Websocketpp 介绍

WebSocketpp 是一个跨平台的开源头部专用 C++ 库,它实现了 RFC6455( WebSocket 协议)和 RFC7692 WebSocketCompression Extensions )。它允许将 WebSocket 客户端和服务器功能集成到 C++ 程序中。在最常见的配置中,全功能网络 I/O Asio 网络库提供。
WebSocketpp 的主要特性包括:
  • 事件驱动的接口
  • 支持 HTTP/HTTPSWS/WSSIPv6
  • 灵活的依赖管理 — Boost /C++11 标准库
  • 可移植性:Posix/Windows32/64bitIntel/ARM
  • 线程安全
下面是该项目的一些常用网站。
  • githubhttps://github.com/zaphoyd/websocketpp
  • 用户手册: http://docs.websocketpp.org/
  • 官网:http://www.zaphoyd.com/websocketpp

安装

sudo apt-get install libboost-dev libboost-system-dev libwebsocketpp-dev

安装完毕后,若在 /usr/include 下有了 websocketpp 目录就表示安装成功了。

websocketpp 常用接口

namespace websocketpp
{
    typedef lib::weak_ptr<void> connection_hdl;

    template <typename config>
    class endpoint : public config::socket_type
    {
        typedef lib::shared_ptr<lib::asio::steady_timer> timer_ptr;
        typedef typename connection_type::ptr connection_ptr;
        typedef typename connection_type::message_ptr message_ptr;
        typedef lib::function<void(connection_hdl)> open_handler;
        typedef lib::function<void(connection_hdl)> close_handler;
        typedef lib::function<void(connection_hdl)> http_handler;
        typedef lib::function<void(connection_hdl, message_ptr)>
            message_handler;
        /* websocketpp::log::alevel::none 禁止打印所有日志*/
        void set_access_channels(log::level channels);   /*设置日志打印等级*/
        void clear_access_channels(log::level channels); /*清除指定等级的日志*/
        /*设置指定事件的回调函数*/
        void set_open_handler(open_handler h);       /*websocket 握手成功回调处理函数*/
        void set_close_handler(close_handler h);     /*websocket 连接关闭回调处理函数*/
        void set_message_handler(message_handler h); /*websocket 消息回调处理函数*/
        void set_http_handler(http_handler h);       /*http 请求回调处理函数*/
        /*发送数据接口*/
        void send(connection_hdl hdl, std::string &payload, frame::opcode::value op);
        void send(connection_hdl hdl, void *payload, size_t len, frame::opcode::value op);
        /*关闭连接接口*/
        void close(connection_hdl hdl, close::status::value code, std::string &reason);
        /*获取 connection_hdl 对应连接的 connection_ptr*/
        connection_ptr get_con_from_hdl(connection_hdl hdl);
        /*websocketpp 基于 asio 框架实现,init_asio 用于初始化 asio 框架中的 io_service 调度器*/
        void init_asio();
        /*设置是否启用地址重用*/
        void set_reuse_addr(bool value);
        /*设置 endpoint 的绑定监听端口*/
        void listen(uint16_t port);
        /*对 io_service 对象的 run 接口封装,用于启动服务器*/
        std::size_t run();
        /*websocketpp 提供的定时器,以毫秒为单位*/
        timer_ptr set_timer(long duration, timer_handler callback);
    };
    template <typename config>
    class server : public endpoint<connection<config>, config>
    {
        /*初始化并启动服务端监听连接的 accept 事件处理*/
        void start_accept();
    };

    template <typename config>
    class connection
        : public config::transport_type::transport_con_type,
          public config::connection_base
    {
        /*发送数据接口*/
        error_code send(std::string &payload, frame::opcode::value op = frame::opcode::text);
        /*获取 http 请求头部*/
        std::string const &get_request_header(std::string const &key);
        /*获取请求正文*/
        std::string const &get_request_body();
        /*设置响应状态码*/
        void set_status(http::status_code::value code);
        /*设置 http 响应正文*/
        void set_body(std::string const &value);
        /*添加 http 响应头部字段*/
        void append_header(std::string const &key, std::string const &val);
        /*获取 http 请求对象*/
        request_type const &get_request();
        /*获取 connection_ptr 对应的 connection_hdl */
        connection_hdl get_handle();
    };

    namespace http
    {
        namespace parser
        {
            class parser
            {
                std::string const &get_header(std::string const &key);
                std::string const &get_body();
                typedef std::map<std::string, std::string,utility::ci_less> header_list;
                header_list const &get_headers();
            };
            class request : public parser
            {
                /*获取请求方法*/
                std::string const &get_method()
                    /*获取请求 uri 接口*/
                    std::string const &get_uri()
            };
        }
    };

    namespace message_buffer
    {
        /*获取 websocket 请求中的 payload 数据类型*/
        frame::opcode::value get_opcode();
        /*获取 websocket 中 payload 数据*/
        std::string const &get_payload();
    };
}

Websocketpp 使用

main.cc
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>

// 1. 定义server类型
typedef websocketpp::server<websocketpp::config::asio> server_t;

void onOpen(websocketpp::connection_hdl hdl)
{
    std::cout << "websocket长连接建立成功!\n";
}
void onClose(websocketpp::connection_hdl hdl)
{
    std::cout << "websocket长连接关闭!\n";
}
void onMessage(server_t *server, websocketpp::connection_hdl hdl, server_t::message_ptr msg)
{
    // 1. 获取有效载荷
    std::string body = msg->get_payload();
    std::cout << "收到消息:" << body << std::endl;
    // 2. 对客户端进行响应
    auto conn = server->get_con_from_hdl(hdl);
    conn->send(body + "-Hello!", websocketpp::frame::opcode::value::text);
}
int main()
{
    // 2. 实例化服务器对象
    server_t server;
    // 3. 初始化日志输出,关闭日志输出
    server.set_access_channels(websocketpp::log::alevel::none);
    // 4. 初始化asio框架
    server.init_asio();
    // 5. 设置消息处理/连接握手成功/关闭连接回调函数
    server.set_open_handler(onOpen);
    server.set_close_handler(onClose);
    auto msg_handler=std::bind(onMessage,&server,std::placeholders::_1,std::placeholders::_2);
    server.set_message_handler(msg_handler);
    // 6. 启用地址重用
    server.set_reuse_addr(true);
    // 7. 设置监听端口
    server.listen(9090);
    // 8. 开始监听
    server.start_accept();
    // 9. 启动服务器
    server.run();
    return 0;
}

makefile

main:main.cc
	g++ -o $@ $^ -std=c++17 -lpthread -lboost_system

test.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Test Websocket</title>
</head>

<body>
    <input type="text" id="message">
    <button id="submit">提交</button>
    <script>
        // 创建 websocket 实例
        // ws://192.168.22.129:9090
        // 类比 http
        // ws 表示 websocket 协议
        let websocket = new WebSocket("ws://192.168.22.129:9090");

        // 处理连接打开的回调函数
        websocket.onopen = function () {
            console.log("连接建立");
        }
        // 处理收到消息的回调函数
        // 控制台打印消息
        websocket.onmessage = function (e) {
            console.log("收到消息: " + e.data);
        }
        // 处理连接异常的回调函数
        websocket.onerror = function () {
            console.log("连接异常");
        }
        // 处理连接关闭的回调函数
        websocket.onclose = function () {
            console.log("连接关闭");
        }
        // 实现点击按钮后, 通过 websocket 实例 向服务器发送请求
        let input = document.querySelector('#message');
        let button = document.querySelector('#submit');
        button.onclick = function () {
            console.log("发送消息: " + input.value);
            websocket.send(input.value);
        } 
    </script>
</body>

</html>

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

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

相关文章

第8章-2 查询执行的基础

上一篇&#xff1a;《第8章-1 查询性能优化-优化数据访问》&#xff0c;接着来了解查询执行的过程&#xff0c;这个对sql执行有个更直观的了解。 查询执行的基础 当希望MySQL能够以更高的性能运行查询时&#xff0c;最好的办法就是弄清楚MySQL是如何优化和执行查询的。一旦理解…

java面试OOM汇总

在正式 Minor GC 前&#xff0c;JVM 会先检查新生代中对象&#xff0c;是比老年代中剩余空间大还是小。假如 Minor GC之后 Survivor 区放不下剩余对象&#xff0c;这些对象就要进入老年代 老年代剩余空间大于新生代中的对象大小&#xff0c;那就直接 Minor GC&#xff0c; GC 完…

react-diff-viewer 如何实现语法高亮

前言 react-diff-viewer 是一个很好的 diff 展示库&#xff0c;但是也有一些坑点和不完善的地方&#xff0c;本文旨在描述如何在这个库中实现自定义语法高亮。 Syntax highlighting is a bit tricky when combined with diff. Here, React Diff Viewer provides a simple rend…

自定义prometheus exporter实现监控阿里云RDS

# 自定义 Prometheus Exporter 实现多 RDS 数据采集## 背景1. Prometheus 官网提供的 MySQL Exporter 对于 MySQL 实例只能一个进程监控一个实例&#xff0c;数据库实例很多的情况下&#xff0c;不方便管理。 2. 内部有定制化监控需求&#xff0c;RDS 默认无法实现&#xff0c;…

【计算机网络】--tcp三次握手

文章目录 示意图&#xff1a;抓包结果&#xff1a;第一次握手&#xff08;Client → Server&#xff09;第二次握手&#xff08;Server → Client&#xff09;第三次握手&#xff08;Client → Server&#xff09;为什么是三次握手 不是两次或者四次 示意图&#xff1a; 抓包结…

UI-TARS: 基于视觉语言模型的多模式代理

GitHub&#xff1a;https://github.com/bytedance/UI-TARS 更多AI开源软件&#xff1a;发现分享好用的AI工具、AI开源软件、AI模型、AI变现 - 小众AI 基于视觉语言模型&#xff08;Vision-Language Model&#xff09;的 GUI 代理应用&#xff0c;允许用户通过自然语言控制电脑操…

Spark SQL 运行架构详解(专业解释+番茄炒蛋例子解读)

1. 整体架构概览 Spark SQL的运行过程可以想象成一个"SQL查询的加工流水线"&#xff0c;从原始SQL语句开始&#xff0c;经过多个阶段的处理和优化&#xff0c;最终变成分布式计算任务执行。主要流程如下&#xff1a; SQL Query → 解析 → 逻辑计划 → 优化 → 物理…

【计算机网络】网络IP层

&#x1f4da; 博主的专栏 &#x1f427; Linux | &#x1f5a5;️ C | &#x1f4ca; 数据结构 | &#x1f4a1;C 算法 | &#x1f152; C 语言 | &#x1f310; 计算机网络 上篇文章&#xff1a;传输层协议TCP 下篇文章&#xff1a;数据链路层 文章摘要&#xff1…

一天学会Maven

一、Maven简介和快速入门 1.1 Maven介绍 Maven 是一款为 Java 项目构建管理、依赖管理的工具&#xff08;软件&#xff09;&#xff0c;使用 Maven 可以自动化构建、测试、打包和发布项目&#xff0c;大大提高了开发效率和质量。 总结&#xff1a;Maven就是一个软件&#xf…

变量函数实战:高保真APP原型“发票页面”动态交互教程

变量函数是高保真交互原型设计中常见的高级交互功能&#xff0c;能够避免重复复制与手动修改页面元素和逻辑标注&#xff0c;让演示更有真实体验感。本文分享一个高保真APP交互原型页面的实操案例&#xff0c;结合原型设计工具中的变量函数与逻辑判断功能&#xff0c;手把手教你…

Spring Boot 3 + Undertow 服务器优化配置

优化背景 当你的application需要支持瞬时高并发的时候&#xff0c;tomcat已经不在是最优的选择&#xff0c;我们可以改为Undertow&#xff0c;并对其进行优化。 Undertow 是一个轻量级的、高性能的Java Web 服务器&#xff0c;由JBoss 开发并开源。它是基于非阻塞&#xff08;…

7系列 之 OSERDESE2

背景 《ug471_7Series_SelectIO.pdf》介绍了Xilinx 7 系列 SelectIO 的输入/输出特性及逻辑资源的相关内容。 第 1 章《SelectIO Resources》介绍了输出驱动器和输入接收器的电气特性&#xff0c;并通过大量实例解析了各类标准接口的实现。 第 2 章《SelectIO Logic Resource…

vue3+flask+sqlite前后端项目实战

基础环境安装 pycharm 下载地址&#xff1a; https://www.jetbrains.com/zh-cn/pycharm/download/?sectionwindows vscode 下载地址 https://code.visualstudio.com/docs/?dvwin64user python 下载地址 https://www.python.org/downloads/windows/ Node.js&#xff08;含npm…

Java 线程的堆栈跟踪信息

Java 线程的堆栈跟踪信息&#xff0c;展示了线程的当前状态和执行位置。以下是详细解释&#xff1a; 线程基本信息 "Thread-0" #16 prio5 os_prio0 cpu0.00ms elapsed16.29s tid0x00000243105a4130 nid0x5384 waiting on condition [0x0000007687ffe000]线程名称…

【计算机视觉】OpenCV实战项目:Long-Exposure:基于深度学习的长时间曝光合成技术

Long-Exposure&#xff1a;基于深度学习的长时间曝光合成技术 项目概述与技术背景项目核心功能技术原理 环境配置与安装硬件要求建议详细安装步骤可选组件安装 实战应用指南1. 基础使用&#xff1a;视频转长曝光2. 高级模式&#xff1a;自定义光轨合成3. 批量处理模式 技术实现…

传输层协议UDP和TCP

传输层协议UDP和TCP 1、UDP2、TCP2.1、TCP协议段格式2.2、确认应答(ACK)机制2.3、超时重传机制2.4、连接管理机制2.5、理解CLOSE_WAIT状态2.6、理解TIME_WAIT状态2.7、流量控制2.8、滑动窗口2.9、拥塞控制2.10、延迟应答2.11、捎带应答2.12、面向字节流2.13、粘包问题2.14、TCP…

浅谈大语言模型原理

1.反向传播算法 背景 反向传播算法是当前深度学习的核心技术。 神经网络 x是输入&#xff0c;o是输出&#xff0c;w是需要训练的参数&#xff08;w有初始值&#xff09;三层全连接的神经网络&#xff1a;输入层、隐藏层、输出层 激活函数 f ( x ) 1 1 x − 1 f(x)\frac…

Clickhouse 迁移到 Doris 的最佳实践

一、引言 在将数据从 Clickhouse 迁移到 Apache Doris / SelectDB Cloud 的过程中&#xff0c;涉及表结构迁移、查询语句迁移以及数据迁移等多个关键环节。每个环节都有其复杂性和需要注意的细节&#xff0c;本文将详细介绍这些内容及对应的最佳实践方法。 二、表结构迁移 &…

WebSocket的原理及QT示例

一.WebSocket 介绍 1.概述 WebSocket 是一种在单个 TCP 连接上进行全双工通讯的协议&#xff0c;它在 2011 年被 IETF 定为标准 RFC 6455&#xff0c;并由 RFC7936 补充规范。与传统的 HTTP 协议不同&#xff0c;WebSocket 允许服务器和客户端之间进行实时、双向的数据传输&a…

vue3:十二、图形看板- echart图表-柱状图、饼图

一、效果 如图展示增加了饼图和柱状图,并且优化了浏览器窗口大小更改,图表随着改变 二、 饼图 1、新建组件文件 新增组件EchartsExaminePie.vue,用于存储审核饼图的图表 2、写入组件信息 (1)视图层 写入一个div,写入变量chart和图表宽高 <template><div ref…