websocketpp 全面使用教程:C++ WebSocket 开发核心

websocketpp 全面使用教程:C++ WebSocket 开发核心

WebSocket 协议

WebSocket 的出现

你是否曾好奇,网页聊天框的消息能秒弹、直播的弹幕能实时滚动、游戏的操作能即时同步,这些「实时互动」的背后,到底藏着怎样的通信魔法?在 WebSocket 出现之前,想要实现网页端的实时数据交互,程序员们只能靠着 HTTP 协议反复 “折腾”—— 让客户端不停向服务器发请求轮询数据,不仅像个 “话痨” 一样反复问 “有没有新消息?”,还会造成服务器资源浪费、消息延迟高的问题,就连简单的即时聊天,都成了技术上的小难题。为了解决 HTTP 协议 “一问一答” 的被动缺陷,让网页端和服务器能像打电话一样双向实时对话,WebSocket 协议应运而生,它以 TCP 为基础,完成一次握手后就能建立长连接,让客户端和服务器想发消息就发消息,彻底颠覆了传统 Web 的通信模式,也成为了现代实时 Web 应用的核心技术之一。

WebSocket 解决了 HTTP 短连接 + 单向通信的核心痛点,实现了客户端与服务器的长连接双向实时通信,让服务器拥有了主动向客户端推送数据的能力

这里注意一下:WebSocket 协议应运而生,它以 TCP 为基础,完成一次握手后就能建立长连接,让客户端和服务器想发消息就发消息 -- 这句话的本质意思是:

TCP 的三次握手是底层建立网络连接的过程(客户端和服务器确认能通信),而 WebSocket 说的 “一次握手”,准确来说是一次 HTTP 协议升级握手—— 本质是借 HTTP 的 “壳” 完成协议切换,之后就不用再反复 “打招呼” 了。

WebSocket 是从 HTML5 开始支持的一种网页端和服务端保持长连接的 消息推送机制,WebSocket 更接近于 TCP 这种级别的通信方式,一 旦连接建立完成客户端或者服务器都可以主动的向对方发送数据。

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

具体协议升级的过程如下:

报文格式​

1. 帧头控制字段(第 1 字节)

FIN(1 bit):表示是否为消息的最后一帧。1 表示这是最后一帧,0 表示还有后续分片帧。

RSV1 / RSV2 / RSV3(各 1 bit):保留位,协议扩展使用,未启用扩展时必须为 0

Opcode(4 bit):定义帧的类型,常见取值:

  • 0x0:延续帧(分片消息的后续帧)
  • 0x1:文本帧(UTF-8 编码)
  • 0x2:二进制帧
  • 0x8:连接关闭帧
  • 0x9:Ping 帧(心跳检测)
  • 0xA:Pong 帧(Ping 响应)

2. 掩码与负载长度字段(第 2 字节)

MASK(1 bit):指示负载数据是否被掩码。客户端发送的帧必须置为 1,服务端发送的帧为 0

Payload Length(7 bit)负载数据的长度,采用可变长度编码:

  • 0–125:直接表示负载长度
  • 126:后续 2 字节(16 位)表示扩展长度
  • 127:后续 8 字节(64 位)表示扩展长度

3. 扩展长度字段(可选)

[扩展用] 16 位 Payload Length:当 Payload Length = 126 时出现,用于表示 126–65535 字节的负载长度。

[扩展用] 32 位 Payload Length:当 Payload Length = 127 时出现,用于表示大于 65535 字节的负载长度。

4. 掩码密钥(可选)

Mask-Key(4 字节 / 32 bit):仅当 MASK = 1 时存在,是一个 4 字节的随机数。客户端使用它对负载数据进行异或(XOR)掩码,服务端用同一密钥解掩码。

5. 负载数据

Payload Data(可变长度):实际传输的应用数据,长度由前面的 Payload Length 字段决定。文本帧为 UTF-8 字符串,二进制帧为原始字节流。

数据帧?请求报头/响应报头?

HTTP:有请求(Request)、有响应(Response),必须一问一答。

WebSocket:没有请求、没有响应!只有「消息」!

所以 WebSocket 他是数据帧,不是请求/响应报头!

HTTP 协议在代码实现上,本质是基于路由注册 + 请求 / 响应模型的处理模式。服务端会维护一张类似哈希表的路由表,以请求方法(如 POST/GET)+ 资源路径 URL 作为唯一键 Key,将其与对应的处理函数地址进行绑定注册。当客户端通过 IP + 端口发送二进制数据流(例如使用 Protobuf 序列化)时,服务端先解析出请求方法与 URL,再根据路由表找到匹配的处理函数;该函数负责将二进制数据反序列化为请求消息,执行业务逻辑后生成响应消息,再序列化为二进制数据发送回客户端,客户端收到响应后再进行后续处理。整个过程严格遵循一问一答的请求 / 响应模式,每次通信都必须依赖路由匹配才能完成处理。

这个具体的代码说明我们可以看:(第三方库)

C++ 轻量级 HTTP 库 cpp-httplib 全面使用教程-ZEEKLOG博客

而 WebSocket 协议在代码实现上完全抛弃了路由与请求 / 响应模型,它只提供一套基础的消息通信接口。开发者不需要注册请求方法、URL 路由,也不需要维护哈希表形式的路由映射;只需要注册对应的消息回调方法,当客户端或服务端任意一方通过长连接发送二进制或文本数据帧时,对方便会直接触发回调方法接收数据。WebSocket 是全双工通信模式,任意一方都可以主动发送消息,不需要等待请求,也不需要按路由匹配处理函数,数据交互的本质是帧的收发与解析,而非 HTTP 式的请求构造与响应生成。

简单来说:HTTP 是按 “地址 + 方法” 找处理函数,是请求转响应;WebSocket 是直接收发消息,是帧处理回调。

这个具体的代码说明我们可以看:(第三方库,在下面)WebSocketpp

websocketpp 第三方库

websocketpp 简介

开发 C++ 实时网络程序时,你是否也有过这样的烦恼:想做一个即时通信、实时数据推送、游戏联机、设备状态同步功能,用传统 HTTP 轮询却效率极低、频繁请求浪费资源,延迟还高得离谱;想手写 WebSocket 协议实现长连接,却要啃晦涩的 RFC 协议文档,手动处理握手升级、数据帧封装 / 解析、心跳保活、断线重连、二进制 / 文本消息处理,光完成基础连接就要写几百行代码;更糟的是,手写的 WebSocket 代码兼容性极差,不支持浏览器、客户端、服务端互通,遇到 TLS 加密、多客户端并发、消息分片就直接崩溃,调试起来毫无头绪。

尤其是遇到实时业务场景:需要服务端主动向客户端推送数据(如监控告警、直播弹幕、物联网数据上报),HTTP 做不到主动推送,轮询又卡顿耗电;想快速实现一个跨平台的 WebSocket 服务端 / 客户端,却要集成多个网络库,配置繁琐、编译报错不断;想兼容标准 WebSocket 协议,和网页、移动端、其他后端互通,手写代码根本无法适配所有客户端,轻则业务无法实现,重则实时功能完全不可用。

而开源的 WebSocket++ 正是为解决这个痛点而来 —— 这款跨平台、高性能、全功能的 C++ WebSocket 库,基于 C++11 标准开发,兼容 RFC 6455 全版本协议,同时支持服务端 + 客户端双模式,内置线程安全、消息分片、心跳保活、SSL/TLS 加密、异步事件驱动等核心能力,无需手动处理底层协议细节,只需几行代码就能搭建稳定的 WebSocket 长连接服务,实现服务端与客户端的双向实时通信,堪称 C++ 实时网络开发的 “终极利器”。

它最大的优势是零依赖、易集成、兼容性拉满:可以直接嵌入项目,支持 Windows/Linux/macOS 全平台,能和网页 WebSocket、移动端 WebSocket、其他语言后端无缝互通,不管是做物联网、实时通信、游戏联机还是数据推送,都能快速落地。

光说不练假把式,我们用一个「WebSocket 服务端 + 客户端双向通信」的例子,快速感受 WebSocket++ 的便捷性:(可以先去看一下安装配置,再来练练手)

如果不清楚 WebSocket 是什么、和 HTTP 的区别,建议先简单了解 WebSocket 长连接协议基础😊


第一步:新建 WebSocket 服务端代码(ws_server.h)

只需包含 WebSocket++ 头文件,无需额外链接库,快速实现客户端连接管理、消息广播、消息接收响应

#ifndef WS_SERVER_H #define WS_SERVER_H // 仅需包含WebSocket++核心头文件 #include <websocketpp/config/asio_no_tls.hpp> #include <websocketpp/server.hpp> #include <iostream> #include <set> #include <mutex> // 定义WebSocket服务器类型 typedef websocketpp::server<websocketpp::config::asio> ws_server; // 全局管理所有连接客户端(用于消息广播) std::set<websocketpp::connection_hdl, std::owner_less<websocketpp::connection_hdl>> g_connections; std::mutex g_conn_mutex; // 收到客户端消息时的回调函数 void on_message(ws_server* s, websocketpp::connection_hdl hdl, ws_server::message_ptr msg) { std::lock_guard<std::mutex> lock(g_conn_mutex); std::string payload = msg->get_payload(); std::cout << "【服务端】收到客户端消息:" << payload << std::endl; // 1. 给当前发送消息的客户端回传消息 std::string reply = "服务端已收到:" + payload; s->send(hdl, reply, websocketpp::frame::opcode::text); // 2. 广播消息给所有已连接的客户端(群聊/全量推送核心功能) for (auto conn : g_connections) { s->send(conn, "[广播] " + payload, websocketpp::frame::opcode::text); } } // 客户端建立连接时的回调 void on_open(ws_server* s, websocketpp::connection_hdl hdl) { std::lock_guard<std::mutex> lock(g_conn_mutex); g_connections.insert(hdl); std::cout << "【服务端】新客户端已连接,当前在线:" << g_connections.size() << std::endl; } // 客户端断开连接时的回调 void on_close(ws_server* s, websocketpp::connection_hdl hdl) { std::lock_guard<std::mutex> lock(g_conn_mutex); g_connections.erase(hdl); std::cout << "【服务端】客户端已断开,当前在线:" << g_connections.size() << std::endl; } // 初始化并启动WebSocket服务端 void InitWebSocketServer() { ws_server svr; // 禁用日志(可选,调试可开启) svr.clear_access_channels(websocketpp::log::alevel::all); svr.clear_error_channels(websocketpp::log::elevel::all); // 初始化Asio底层网络 svr.init_asio(); // 绑定回调函数 svr.set_open_handler(bind(&on_open, &svr, std::placeholders::_1)); svr.set_close_handler(bind(&on_close, &svr, std::placeholders::_1)); svr.set_message_handler(bind(&on_message, &svr, std::placeholders::_1, std::placeholders::_2)); // 监听 0.0.0.0:9002 端口 svr.listen("0.0.0.0", 9002); std::cout << "WebSocket 服务已启动:ws://localhost:9002" << std::endl; // 启动服务(阻塞运行) svr.run(); } #endif // WS_SERVER_H 

第二步:新建 WebSocket 客户端 + 主程序(main.cpp)

实现主动连接服务端、发送消息、接收服务端消息,同步 / 异步都支持:

#include "ws_server.h" #include <websocketpp/config/asio_no_tls_client.hpp> #include <websocketpp/client.hpp> #include <iostream> #include <thread> #include <string> // 定义WebSocket客户端类型 typedef websocketpp::client<websocketpp::config::asio_client> ws_client; // 客户端收到服务端消息回调 void on_client_message(websocketpp::connection_hdl hdl, ws_client::message_ptr msg) { std::cout << "【客户端】收到服务端消息:" << msg->get_payload() << std::endl; } // WebSocket客户端测试逻辑 void WebSocketClientDemo() { ws_client cli; // 禁用日志 cli.clear_access_channels(websocketpp::log::alevel::all); cli.clear_error_channels(websocketpp::log::elevel::all); cli.init_asio(); cli.set_message_handler(&on_client_message); // 创建连接 websocketpp::lib::error_code ec; ws_client::connection_ptr conn = cli.get_connection("ws://localhost:9002", ec); cli.connect(conn); // 启动客户端网络线程 std::thread cli_thread([&]() { cli.run(); }); // 等待连接建立 std::this_thread::sleep_for(std::chrono::milliseconds(500)); // 向服务端发送消息 std::string send_msg = "Hello WebSocket++!"; std::cout << "【客户端】发送消息:" << send_msg << std::endl; cli.send(conn->get_handle(), send_msg, websocketpp::frame::opcode::text); // 保持运行3秒,接收广播/回复消息 std::this_thread::sleep_for(std::chrono::seconds(3)); // 关闭连接 cli.close(conn->get_handle(), websocketpp::close::status::normal, "exit"); cli_thread.join(); } int main() { // 子线程启动WebSocket服务端(避免阻塞) std::thread server_thread(InitWebSocketServer); std::this_thread::sleep_for(std::chrono::seconds(1)); // 运行客户端测试 WebSocketClientDemo(); server_thread.join(); return 0; } 

WebSocket++ 依赖 Boost.Asio(或独立 Asio),常规编译命令:

# 创建可执行文件(需安装boost/asio) g++ main.cpp -std=c++11 -lpthread -lboost_system -o ws_demo # 运行 ./ws_demo 
WebSocket 服务已启动:ws://localhost:9002 【服务端】新客户端已连接,当前在线:1 【客户端】发送消息:Hello WebSocket++! 【服务端】收到客户端消息:Hello WebSocket++! 【客户端】收到服务端消息:服务端已收到:Hello WebSocket++! 【客户端】收到服务端消息:[广播] Hello WebSocket++! 【服务端】客户端已断开,当前在线:0 

我们可以用浏览器原生 WebSocket 连接这个 C++ 服务端,实现网页和 C++ 程序实时互通:

// 浏览器控制台直接运行 let ws = new WebSocket("ws://localhost:9002"); ws.onmessage = (e) => console.log("网页收到:", e.data); ws.send("我是网页客户端"); 

我们的 C++ 服务端会立刻收到消息,并向网页推送广播数据,真正做到跨平台、跨语言互通


WebSocket++ 让我们彻底告别底层协议和网络编程噩梦,专注业务逻辑:

双向实时通信:服务端可主动推送,无需轮询,延迟毫秒级

服务端 + 客户端双模式:一套代码实现两种角色

全协议兼容:完美支持所有标准 WebSocket 客户端(浏览器、小程序、APP、Java/Python/Go 后端)

高性能并发:支持海量客户端连接,异步 I/O,线程安全

极易扩展

  • 加 SSL 加密:只需切换为 asio_tls 配置
  • 加心跳保活:几行代码实现
  • 加二进制数据传输:直接支持图片 / 文件 / 自定义协议

安装

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

常用接口介绍

在 WebSocket++ 中,所有功能都由两个核心部分决定:

  1. Role(角色):你要写 服务端 还是 客户端
  2. Config(配置):是否使用 Asio、是否开启 TLS(wss)

组合后得到 EndPoint(最终实例 server or client)。

// 服务端角色 #include <websocketpp/server.hpp> // 客户端角色 #include <websocketpp/client.hpp> 
配置类
配置依赖协议用途
core无(C++11)ws最小功能,无异步
asioBoost.Asiows完整功能,推荐使用
asio_tlsBoost.Asio + TLSwss加密通信

WebSocket++ 所有功能都依赖配置类,决定:是否开启 TLS、是否使用 Asio、日志级别、缓冲区大小等。只用记 4 个最常用的

1. websocketpp::config::asio_no_tls

用途:非加密 WebSocket 服务端配置(ws://)

// 最基础:无 TLS,使用 Asio 异步网络,纯 TCP 长连接 #include <websocketpp/config/asio_no_tls.hpp> using WSConfig = websocketpp::config::asio_no_tls; 

2. websocketpp::config::asio_tls

用途:加密 WebSocket 服务端配置(wss://)

// 带 TLS/SSL 加密,用于生产环境(https 配套 wss) #include <websocketpp/config/asio_tls.hpp> using WSSConfig = websocketpp::config::asio_tls; 

3. websocketpp::config::asio_no_tls_client

用途:非加密 WebSocket 客户端配置

// 客户端专用无 TLS 配置 #include <websocketpp/config/asio_no_tls_client.hpp> using WSClientConfig = websocketpp::config::asio_no_tls_client; 

4. websocketpp::config::asio_tls_client

用途:加密 WebSocket 客户端配置(wss://)

// 客户端访问 wss 接口必须用这个 #include <websocketpp/config/asio_tls_client.hpp> using WSSClientConfig = websocketpp::config::asio_tls_client; 

服务端类

websocketpp::server<Config>

全称websocketpp::server<websocketpp::config::asio_no_tls>

作用:创建 WebSocket 服务端,监听端口、管理客户端连接、收发消息。

常用成员函数

// 1. 定义服务端类型(别名简化代码,必写) typedef websocketpp::server<websocketpp::config::asio_no_tls> WSServer; WSServer svr; // 创建服务端实例 // -------------------------- 初始化 -------------------------- // 初始化 Asio 底层网络框架(必须调用) svr.init_asio(); // -------------------------- 日志控制 -------------------------- // 关闭所有访问日志(测试用,减少打印) svr.clear_access_channels(websocketpp::log::alevel::all); // 关闭所有错误日志(正式环境建议打开) svr.clear_error_channels(websocketpp::log::elevel::all); // -------------------------- 回调绑定(核心!) -------------------------- // 客户端建立连接时触发 svr.set_open_handler(std::bind(&on_open, &svr, std::placeholders::_1)); // 客户端断开连接时触发 svr.set_close_handler(std::bind(&on_close, &svr, std::placeholders::_1)); // 收到客户端消息时触发 svr.set_message_handler(std::bind(&on_message, &svr, std::placeholders::_1, std::placeholders::_2)); // 连接失败/错误时触发 svr.set_fail_handler(std::bind(&on_fail, &svr, std::placeholders::_1)); // -------------------------- 监听与启动 -------------------------- // 监听 IP + 端口(0.0.0.0 表示所有网卡都能访问) svr.listen("0.0.0.0", 9002); // 启动服务端事件循环(阻塞运行,必须放在最后) svr.run(); // -------------------------- 主动发消息(服务端 -> 客户端) -------------------------- // hdl:连接句柄 msg:消息内容 opcode:文本/二进制 svr.send(hdl, msg, websocketpp::frame::opcode::text); // -------------------------- 主动关闭连接 -------------------------- svr.close(hdl, websocketpp::close::status::normal, "主动断开"); 

客户端类

websocketpp::client<Config>

全称websocketpp::client<websocketpp::config::asio_no_tls_client>

作用:创建 WebSocket 客户端,连接服务端、发送 / 接收消息。

常用成员函数

// 1. 定义客户端类型 typedef websocketpp::client<websocketpp::config::asio_no_tls_client> WSClient; WSClient cli; // 创建客户端实例 // -------------------------- 初始化 -------------------------- cli.init_asio(); // -------------------------- 日志关闭 -------------------------- cli.clear_access_channels(websocketpp::log::alevel::all); cli.clear_error_channels(websocketpp::log::elevel::all); // -------------------------- 回调绑定 -------------------------- // 收到服务端消息 cli.set_message_handler(&on_client_message); // 连接成功 cli.set_open_handler(&on_client_open); // 断开连接 cli.set_close_handler(&on_client_close); // -------------------------- 连接服务端 -------------------------- websocketpp::lib::error_code ec; // 错误码接收 // 创建连接 WSClient::connection_ptr conn = cli.get_connection("ws://127.0.0.1:9002", ec); // 发起连接 cli.connect(conn); // -------------------------- 启动客户端事件循环 -------------------------- cli.run(); // 阻塞,一般放子线程 // -------------------------- 发送消息 -------------------------- cli.send(conn->get_handle(), "Hello", websocketpp::frame::opcode::text); 

连接句柄类

websocketpp::connection_hdl

作用:唯一标识一个客户端连接,类似 “客户端 ID”。

特点:轻量级、不能直接存储,必须用 std::owner_less 修饰。

用法示例

// 正确存储所有客户端连接(必须用 set + owner_less) std::set<websocketpp::connection_hdl, std::owner_less<websocketpp::connection_hdl>> clients; // 回调函数里获取句柄 void on_open(websocketpp::connection_hdl hdl) { clients.insert(hdl); // 加入连接列表 } void on_close(websocketpp::connection_hdl hdl) { clients.erase(hdl); // 移除断开的连接 } 

消息类【收消息必用】

websocketpp::message_ptr

作用:封装客户端 / 服务端发来的消息(文本 / 二进制、长度、是否分片)。

核心成员函数

// 消息类型别名(WebSocket++ 统一用智能指针) typedef WSServer::message_ptr message_ptr; // 消息回调函数 void on_message(WSServer* svr, websocketpp::connection_hdl hdl, message_ptr msg) { // -------------------------- 获取消息内容 -------------------------- std::string content = msg->get_payload(); // 获取消息字符串 // -------------------------- 获取消息长度 -------------------------- size_t len = msg->get_payload_length(); // -------------------------- 判断消息类型 -------------------------- bool is_text = msg->get_opcode() == websocketpp::frame::opcode::text; bool is_binary = msg->get_opcode() == websocketpp::frame::opcode::binary; // -------------------------- 打印 -------------------------- std::cout << "收到消息:" << content << std::endl; } 

连接智能指针

websocketpp::connection_ptr

作用:客户端专用,管理连接状态、获取句柄、获取远程地址。

常用方法

// 获取连接句柄(用于发消息) auto hdl = conn->get_handle(); // 获取对端 IP 地址 std::string ip = conn->get_remote_endpoint(); // 获取请求头(如 token、Origin) std::string token = conn->get_request_header("token"); 

帧操作码类(Opcode)【消息类型】

websocketpp::frame::opcode

作用:指定消息是文本还是二进制(图片 / 文件 / 自定义数据)。

using namespace websocketpp::frame; opcode::text; // 文本消息(JSON/字符串) opcode::binary; // 二进制消息(图片、文件、protobuf) opcode::ping; // 心跳 ping opcode::pong; // 心跳 pong 

关闭状态类

websocketpp::close::status

作用:断开连接时指定关闭原因码。

using namespace websocketpp::close; status::normal; // 正常关闭 status::going_away; // 服务端退出 status::protocol_error; // 协议错误 status::unsupported_data; // 不支持的数据类型 

日志通道类
// 关闭日志 svr.clear_access_channels(websocketpp::log::alevel::all); svr.clear_error_channels(websocketpp::log::elevel::all); 

最常用组合类
1. 服务端全套(开发必用)
#include <websocketpp/config/asio_no_tls.hpp> #include <websocketpp/server.hpp> // 服务端类型定义(最常用) typedef websocketpp::server<websocketpp::config::asio_no_tls> WSServer; // 消息类型 typedef WSServer::message_ptr message_ptr; // 连接句柄 using websocketpp::connection_hdl; 
2. 客户端全套
#include <websocketpp/config/asio_no_tls_client.hpp> #include <websocketpp/client.hpp> // 客户端类型定义 typedef websocketpp::client<websocketpp::config::asio_no_tls_client> WSClient; // 连接指针 typedef WSClient::connection_ptr connection_ptr;

Role + Config 组合表(开发查表即可)

服务端组合

// 1. 基础无Asio(极少用) #include <websocketpp/server.hpp> #include <websocketpp/config/core.hpp> typedef websocketpp::server<websocketpp::config::core> server; // 2. Asio + ws(开发 90% 用这个) #include <websocketpp/server.hpp> #include <websocketpp/config/asio_no_tls.hpp> typedef websocketpp::server<websocketpp::config::asio> server; // 3. Asio + wss(加密服务端) #include <websocketpp/server.hpp> #include <websocketpp/config/asio.hpp> typedef websocketpp::server<websocketpp::config::asio_tls> server; 

客户端组合

// 1. 基础无Asio #include <websocketpp/client.hpp> #include <websocketpp/config/core_client.hpp> typedef websocketpp::client<websocketpp::config::core_client> client; // 2. Asio + ws(最常用) #include <websocketpp/client.hpp> #include <websocketpp/config/asio_no_tls_client.hpp> typedef websocketpp::client<websocketpp::config::asio_client> client; // 3. Asio + wss(加密客户端) #include <websocketpp/client.hpp> #include <websocketpp/config/asio_client.hpp> typedef websocketpp::client<websocketpp::config::asio_tls_client> client; 

WebSocket++ 固定开发步骤

服务端步骤:

  1. 包含头文件
  2. 定义 EndPoint
  3. 初始化 Asio
  4. 绑定回调(open/close/fail/message)
  5. 监听端口
  6. 开始接受连接
  7. 运行事件循环

客户端步骤:

  1. 包含头文件
  2. 定义 EndPoint
  3. 初始化 Asio
  4. 绑定回调
  5. 创建连接
  6. 发起连接
  7. 运行事件循环

完整版代码(服务端 + 客户端 + WSS)


【1】WebSocket 服务端(ws://)最常用
#include <websocketpp/server.hpp> #include <websocketpp/config/asio_no_tls.hpp> #include <iostream> #include <string> using namespace std; using websocketpp::lib::bind; using websocketpp::lib::placeholders::_1; using websocketpp::lib::placeholders::_2; // 定义服务端类型(Asio + 无加密) typedef websocketpp::server<websocketpp::config::asio> server; typedef server::message_ptr message_ptr; // 收到消息回调 void on_message(server* s, websocketpp::connection_hdl hdl, message_ptr msg) { cout << "收到消息:" << msg->get_payload() << endl; // 回声模式:原样返回 try { s->send(hdl, msg->get_payload(), msg->get_opcode()); } catch (websocketpp::exception& e) { cout << "发送失败:" << e.what() << endl; } } // 连接建立回调 void on_open(server* s, websocketpp::connection_hdl hdl) { cout << "客户端已连接" << endl; } // 连接关闭回调 void on_close(server* s, websocketpp::connection_hdl hdl) { cout << "客户端已断开" << endl; } int main() { server srv; try { // 日志设置 srv.set_access_channels(websocketpp::log::alevel::all); srv.clear_access_channels(websocketpp::log::alevel::frame_payload); // 初始化Asio srv.init_asio(); // 绑定回调 srv.set_open_handler(bind(&on_open, &srv, _1)); srv.set_close_handler(bind(&on_close, &srv, _1)); srv.set_message_handler(bind(&on_message, &srv, _1, _2)); // 监听端口 srv.listen(9002); // 开始接受连接 srv.start_accept(); cout << "WebSocket 服务已启动:ws://127.0.0.1:9002" << endl; // 启动事件循环 srv.run(); } catch (websocketpp::exception& e) { cout << e.what() << endl; } return 0; } 

我们可以在桌面上创建一个临时的 html 格式文件,写入:

<!DOCTYPE html> <html> <body> <script> const ws = new WebSocket("ws://192.168.10.129:9002"); ws.onmessage = (e) => console.log("收到服务端消息:" + e.data); ws.onopen = () => { console.log("连接成功!"); ws.send("Hello WebSocket"); }; </script> </body> </html>

我们运行服务器,点击进入浏览器:

WebSocket 服务已启动:ws://192.168.10.129:9002 [2026-03-02 19:14:23] [connect] WebSocket Connection [::ffff:192.168.10.1]:53293 v13 "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36 Edg/145.0.0.0" / 101 客户端已连接 收到消息:Hello WebSocket [2026-03-02 19:14:23] [frame_header] Dispatching write containing 1 message(s) containing 2 header bytes and 15 payload bytes [2026-03-02 19:14:23] [frame_header] Header Bytes: [0] (2) 81 0F [2026-03-02 19:14:27] [control] Control frame received with opcode 8 [2026-03-02 19:14:27] [frame_header] Dispatching write containing 1 message(s) containing 2 header bytes and 2 payload bytes [2026-03-02 19:14:27] [frame_header] Header Bytes: [0] (2) 88 02 [2026-03-02 19:14:27] [error] handle_read_frame error: websocketpp.transport:7 (End of File) 客户端已断开 [2026-03-02 19:14:27] [disconnect] Disconnect close local:[1006,End of File] remote:[1001]

【2】WebSocket 客户端(ws://)
#include <websocketpp/client.hpp> #include <websocketpp/config/asio_no_tls_client.hpp> #include <iostream> #include <string> using namespace std; using websocketpp::lib::bind; using websocketpp::lib::placeholders::_1; using websocketpp::lib::placeholders::_2; // 定义客户端类型 typedef websocketpp::client<websocketpp::config::asio_client> client; typedef client::message_ptr message_ptr; // 收到消息 void on_message(client* c, websocketpp::connection_hdl hdl, message_ptr msg) { cout << "服务端回复:" << msg->get_payload() << endl; } // 连接成功 void on_open(client* c, websocketpp::connection_hdl hdl) { cout << "连接服务端成功" << endl; c->send(hdl, "Hello WebSocket++", websocketpp::frame::opcode::text); } int main() { client cli; string uri = "ws://127.0.0.1:9002"; try { cli.set_access_channels(websocketpp::log::alevel::all); cli.clear_access_channels(websocketpp::log::alevel::frame_payload); cli.init_asio(); cli.set_open_handler(bind(&on_open, &cli, _1)); cli.set_message_handler(bind(&on_message, &cli, _1, _2)); websocketpp::lib::error_code ec; client::connection_ptr conn = cli.get_connection(uri, ec); cli.connect(conn); cli.run(); } catch (websocketpp::exception& e) { cout << e.what() << endl; } return 0; } 

【3】WSS 客户端(wss://)加密版本
#include <websocketpp/client.hpp> #include <websocketpp/config/asio_client.hpp> #include <iostream> #include <memory> using namespace std; using websocketpp::lib::bind; using websocketpp::lib::placeholders::_1; using websocketpp::lib::placeholders::_2; // WSS 客户端类型 typedef websocketpp::client<websocketpp::config::asio_tls_client> client; typedef client::message_ptr message_ptr; typedef shared_ptr<boost::asio::ssl::context> context_ptr; // TLS 初始化 context_ptr on_tls_init(websocketpp::connection_hdl hdl) { context_ptr ctx = make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::sslv23); try { ctx->set_options( boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::no_sslv3 ); } catch (exception& e) { cout << "TLS 错误:" << e.what() << endl; } return ctx; } // 收到消息 void on_message(client* c, websocketpp::connection_hdl hdl, message_ptr msg) { cout << "WSS 回复:" << msg->get_payload() << endl; } int main() { client cli; string uri = "wss://example.com/websocket"; try { cli.init_asio(); cli.set_tls_init_handler(bind(&on_tls_init, _1)); cli.set_message_handler(bind(&on_message, &cli, _1, _2)); websocketpp::lib::error_code ec; client::connection_ptr conn = cli.get_connection(uri, ec); cli.connect(conn); cli.run(); } catch (websocketpp::exception& e) { cout << e.what() << endl; } return 0; } 

Read more

【大数据存储与管理】分布式文件系统HDFS:05 HDFS存储原理

【大数据存储与管理】分布式文件系统HDFS:05 HDFS存储原理

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈大数据技术原理与应用 ⌋ ⌋ ⌋专栏系统介绍大数据的相关知识,分为大数据基础篇、大数据存储与管理篇、大数据处理与分析篇、大数据应用篇。内容包含大数据概述、大数据处理架构Hadoop、分布式文件系统HDFS、分布式数据库HBase、NoSQL数据库、云数据库、MapReduce、Hadoop再探讨、数据仓库Hive、Spark、流计算、Flink、图计算、数据可视化,以及大数据在互联网领域、生物医学领域的应用和大数据的其他应用。 【GitCode】专栏资源保存在我的GitCode仓库:https://gitcode.com/Morse_Chen/BigData_principle_application。 文章目录 * 一、数据的冗余存储 * 二、数据存取策略 * (一)数据存放 * (二)数据读取 * (三)数据复制 * 三、数据错误与恢复 * (一)

By Ne0inhk
Flutter 三方库 image_compare_2 的鸿蒙化适配指南 - 实现像素级的图像分块对比、支持感知哈希(pHash)与端侧视觉差异检测实战

Flutter 三方库 image_compare_2 的鸿蒙化适配指南 - 实现像素级的图像分块对比、支持感知哈希(pHash)与端侧视觉差异检测实战

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 image_compare_2 的鸿蒙化适配指南 - 实现像素级的图像分块对比、支持感知哈希(pHash)与端侧视觉差异检测实战 前言 在进行 Flutter for OpenHarmony 的图像处理、自动化 UI 测试或内容防侵权应用开发时,如何科学地判断两张图片是否“相似”?简单的字节对比显然无法处理微小的色差或尺寸缩放。image_compare_2 是一个功能完备的图像对比算法库。它支持从均值哈希(aHash)到分块均方差(MSE)等多种度量算法。本文将指导大家如何在鸿蒙真机上利用该库构建精准的视觉检测链路。 一、原原理性解析 / 概念介绍 1.1 基础原理 image_compare_2 通过将原始图片灰度化、缩小尺寸并进行频域变换(或像素聚合)

By Ne0inhk

YOLOv9摄像头实时检测,python detect_dual.py命令详解

YOLOv9摄像头实时检测,python detect_dual.py命令详解 在当前智能视觉应用快速发展的背景下,YOLOv9凭借其卓越的精度与推理效率,成为目标检测领域的新标杆。本镜像基于官方代码库构建,预装完整深度学习环境,支持开箱即用的训练、推理与评估流程。本文将重点解析如何使用python detect_dual.py实现摄像头实时检测,并深入剖析该命令的核心参数配置、运行逻辑及工程实践要点。 1. 环境准备与基础调用 1.1 镜像环境初始化 本镜像已集成以下关键组件: * PyTorch 1.10.0 + CUDA 12.1:保障高性能GPU推理 * OpenCV-Python:用于视频流采集与图像处理 * YOLOv9官方代码库:位于 /root/yolov9 * 预置权重文件 yolov9-s.pt:无需额外下载即可启动推理 启动容器后,首先激活专用conda环境: conda activate yolov9 cd /root/yolov9

By Ne0inhk

两周时间,我从Python零基础到做出准确率97%的AI应用

🚀 从零开始:我的第一个机器学习项目(猫狗识别器) 用两周时间,从Python零基础到部署一个准确率97%的AI应用 📌 前言 作为一个完全零基础的小白,我一直觉得“机器学习”是个很高深的名词。直到两周前,我决定动手试试——从搭建环境开始,一步步完成了一个猫狗图像分类器。现在,它已经是一个可以在浏览器里运行的Web应用了! 项目地址:https://github.com/Hinatatoo/cat-dog-classifier 🎯 项目目标 做一个能区分猫和狗的AI模型,并把它部署成网页应用,让任何人都能上传图片测试。 📊 最终成果 指标结果验证集准确率97%训练时间约2小时(含优化)模型大小27MB识别速度<1秒 🛣️ 学习路线 第1天:环境搭建 * 安装Python 3.10 * 配置VS Code * 创建虚拟环境 ml_env * 安装TensorFlow、Streamlit等库 遇到的坑:pip 找不到命令

By Ne0inhk