C++ 网络编程(22) beast网络库实现websocket服务器

📅 发布时间:2026/7/12 17:13:37 👁️ 浏览次数:
C++ 网络编程(22) beast网络库实现websocket服务器
一、const.h全局头文件与命名空间定义作用汇总项目所有依赖头文件定义命名空间别名防止头文件重复包含作为项目基础头文件#pragmaonce// 防止头文件被重复包含保证全局只引入一次// 标准输入输出头文件用于控制台日志打印#includeiostream// Boost.Asio核心库提供异步网络IO、套接字、事件循环支持#includeboost/asio.hpp// Boost.Beast库封装WebSocket/HTTP协议实现WebSocket通信核心逻辑#includeboost/beast.hpp// 内存操作相关头文件项目预留使用#includememory.h// Boost UUID库用于生成每个连接的唯一标识ID#includeboost/uuid/uuid.hpp#includeboost/uuid/uuid_io.hpp#includeboost/uuid/uuid_generators.hpp// 队列容器用于存储待发送的消息保证消息顺序发送#includequeue// 互斥锁保证多线程环境下消息队列操作的线程安全#includemutex// 命名空间别名简化代码书写避免冗长的全命名空间写法namespacenetboost::asio;namespacebeastboost::beast;// 直接引入WebSocket相关命名空间方便直接调用相关类和函数usingnamespaceboost::beast;usingnamespaceboost::beast::websocket;二、Connection.h单个WebSocket连接类头文件作用封装单个客户端WebSocket连接的所有功能定义类成员变量和成员函数接口继承智能指针相关类解决异步回调生命周期问题#pragmaonce// 引入全局基础头文件#includeconst.h// 单个WebSocket连接处理类// 继承std::enable_shared_from_this用于在异步回调中获取自身的shared_ptr防止对象提前销毁导致野指针classConnection:publicstd::enable_shared_from_thisConnection{public:// 构造函数// 参数ioc - 异步IO上下文引用传递复用全局IO上下文Connection(net::io_contextioc);// 获取当前连接的唯一UUID标识std::stringGetUid();// 获取底层TCP套接字供服务器监听端接收连接使用net::ip::tcp::socketGetSocket();// 异步执行WebSocket握手将TCP连接升级为WebSocket连接voidAsyncAccept();// 启动连接开始监听客户端消息进入读写循环voidStart();// 异步发送消息给客户端// 参数msg - 要发送的字符串消息voidAsyncSend(std::string msg);private:// WebSocket流对象封装底层TCP流unique_ptr保证独占所有权禁止拷贝std::unique_ptrstreamtcp_stream_ws_ptr;// 当前连接的唯一UUID字符串用于连接管理和标识std::string _uuids;// 全局IO上下文引用复用服务端事件循环net::io_context_ioc;// 接收数据缓冲区Beast提供的高效缓冲区存储客户端发送的消息flat_buffer _recv_buffer;// 消息发送队列缓存待发送消息避免并发发送冲突std::queuestd::string_send_que;// 发送队列互斥锁保证多线程操作队列时的线程安全std::mutex _send_mtx;};三、Connection.cpp单个WebSocket连接类实现作用实现Connection类的所有成员函数处理WebSocket握手、消息读取、消息发送、连接维护等核心逻辑#includeConnection.h// 引入连接管理器用于注册和移除当前连接#includeConnectionMgr.h// 构造函数实现// 初始化IO上下文引用创建WebSocket流对象生成唯一UUIDConnection::Connection(net::io_contextioc):_ioc(ioc),// 创建WebSocket流绑定strand保证异步回调单线程执行避免多线程冲突_ws_ptr(std::make_uniquestreamtcp_stream(make_strand(ioc))){// 创建UUID生成器生成随机唯一IDboost::uuids::random_generator generator;boost::uuids::uuid uuidgenerator();// 将UUID转换为字符串存储为当前连接标识_uuidsboost::uuids::to_string(uuid);}// 获取当前连接唯一UUID的实现std::stringConnection::GetUid(){return_uuids;}// 获取底层TCP套接字实现// 通过get_lowest_layer获取WebSocket流最底层的TCP套接字net::ip::tcp::socketConnection::GetSocket(){returnboost::beast::get_lowest_layer(*_ws_ptr).socket();}// 异步WebSocket握手实现// 等待客户端发起握手请求完成协议升级voidConnection::AsyncAccept(){// 获取自身智能指针保证异步回调期间对象不被销毁autoselfshared_from_this();// 异步接受WebSocket握手回调函数处理握手结果_ws_ptr-async_accept([self](boost::system::error_code err){try{// 错误码为空代表握手成功if(!err){// 将当前连接加入全局连接管理器统一管理ConnectionMgr::GetInstance().AddConnection(self);// 握手成功启动连接开始监听消息self-Start();}else{// 握手失败打印错误信息std::coutwebsocket accept failed, err is err.what()std::endl;}}catch(std::exceptionexp){// 捕获异常防止程序崩溃打印异常信息std::coutwebsocket async accept exception is exp.what();}});}// 启动连接进入消息读取循环voidConnection::Start(){// 获取自身智能指针autoselfshared_from_this();// 异步读取客户端发送的消息数据存入接收缓冲区_ws_ptr-async_read(_recv_buffer,[self](error_code err,size_t buffer_bytes){try{// 读取出现错误代表连接断开或异常if(err){std::coutwebsocket async read error is err.what();// 从连接管理器移除当前连接释放资源ConnectionMgr::GetInstance().RmvConnection(self-GetUid());return;}// 设置发送消息类型与客户端发送类型一致文本/二进制self-_ws_ptr-text(self-_ws_ptr-got_text());// 将缓冲区数据转换为字符串方便处理std::string recv_databoost::beast::buffers_to_string(self-_recv_buffer.data());// 清空接收缓冲区准备下一次读取self-_recv_buffer.consume(self-_recv_buffer.size());// 打印接收到的客户端消息std::coutwebsocket receive msg is recv_datastd::endl;// 将接收到的消息回传给客户端回声模式self-AsyncSend(std::move(recv_data));// 递归调用Start持续监听客户端后续消息self-Start();}catch(std::exceptionexp){// 捕获异常打印信息并移除连接std::coutexception is exp.what()std::endl;ConnectionMgr::GetInstance().RmvConnection(self-GetUid());}});}// 异步发送消息实现// 通过队列保证消息顺序发送避免并发发送导致的问题voidConnection::AsyncSend(std::string msg){{// 加锁保证队列操作的线程安全std::lock_guardstd::mutexlck_guard(_send_mtx);// 获取当前队列长度intque_len_send_que.size();// 将消息加入发送队列_send_que.push(msg);// 如果队列原本不为空说明已有消息在发送直接返回等待上一条发送完成if(que_len0){return;}}// 获取自身智能指针autoselfshared_from_this();// 异步发送消息将字符串转为asio缓冲区发送_ws_ptr-async_write(boost::asio::buffer(msg.c_str(),msg.length()),[self](error_code err,std::size_t nsize){try{// 发送失败打印错误并移除连接if(err){std::coutasync_send err iserr.what()std::endl;ConnectionMgr::GetInstance().RmvConnection(self-GetUid());return;}std::string send_msg;{// 加锁操作发送队列std::lock_guardstd::mutexlck_gurad(self-_send_mtx);// 移除已发送完成的消息self-_send_que.pop();// 队列为空无后续消息直接返回if(self-_send_que.empty()){return;}// 获取队列中下一条待发送消息send_msgself-_send_que.front();// 发送下一条消息self-AsyncSend(std::move(send_msg));}}catch(std::exceptionexp){// 捕获异常处理连接std::coutexception is exp.what()std::endl;ConnectionMgr::GetInstance().RmvConnection(self-GetUid());}});}四、ConnectionMgr.h连接管理器头文件作用单例模式实现全局连接管理器统一管理所有客户端连接提供添加、移除连接接口#pragmaonce// 引入全局头文件#includeconst.h// Boost无序哈希表用于存储连接查询效率更高#includeboost/unordered_map.hpp// 引入连接类#includeConnection.h// 连接管理类采用单例模式全局唯一classConnectionMgr{public:// 获取单例实例静态局部变量实现线程安全staticConnectionMgrGetInstance();// 添加新连接到管理器// 参数conptr - 连接对象的智能指针voidAddConnection(std::shared_ptrConnectionconptr);// 根据UUID移除连接// 参数id - 连接的唯一UUIDvoidRmvConnection(std::string);public:// 禁用拷贝构造函数防止单例被拷贝ConnectionMgr(constConnectionMgr)delete;// 禁用赋值运算符保证单例唯一性ConnectionMgroperator(constConnectionMgr)delete;// 构造函数私有化禁止外部创建实例ConnectionMgr();// 存储所有活跃连接key为UUIDvalue为连接智能指针boost::unordered_mapstd::string,std::shared_ptrConnection_map_cons;};五、ConnectionMgr.cpp连接管理器实现作用实现单例连接管理器的具体功能完成连接的添加、移除操作#includeConnectionMgr.h// 获取单例实例实现// 静态局部变量在程序运行期间只初始化一次保证全局唯一ConnectionMgrConnectionMgr::GetInstance(){staticConnectionMgr instance;returninstance;}// 添加连接实现// 将连接的UUID作为键智能指针作为值存入哈希表voidConnectionMgr::AddConnection(std::shared_ptrConnectionconptr){_map_cons[conptr-GetUid()]conptr;}// 移除连接实现// 根据UUID删除哈希表中对应的连接项voidConnectionMgr::RmvConnection(std::string id){_map_cons.erase(id);}// 构造函数实现空实现ConnectionMgr::ConnectionMgr(){}六、WebSocketServer.h服务器核心类头文件作用定义WebSocket服务器核心类负责监听端口、异步接收客户端TCP连接#pragmaonce// 引入全局头文件#includeconst.h// 引入连接管理器#includeConnectionMgr.h// WebSocket服务器核心类classWebSocketServer{public:// 禁用拷贝构造防止服务器对象被拷贝WebSocketServer(constWebSocketServer)delete;// 禁用赋值运算符WebSocketServeroperator(constWebSocketServer)delete;// 构造函数// 参数ioc - 全局IO上下文port - 服务器监听端口WebSocketServer(net::io_contextioc,unsignedshortport);// 开始异步监听客户端连接voidStartAccept();private:// TCP接收器负责监听端口接收客户端TCP连接net::ip::tcp::acceptor _acceptor;// 全局IO上下文引用net::io_context_ioc;};七、WebSocketServer.cpp服务器核心类实现作用实现服务器监听、接收客户端连接的逻辑循环接收新连接分配给对应连接对象处理#includeWebSocketServer.h// 构造函数实现// 初始化接收器绑定指定端口监听所有网卡WebSocketServer::WebSocketServer(net::io_contextioc,unsignedshortport):_ioc(ioc),// 绑定IPv4地址和指定端口开启监听_acceptor(ioc,net::ip::tcp::endpoint(net::ip::tcp::v4(),port)){// 打印服务器启动信息显示监听端口std::coutServer start on port :portstd::endl;}// 开始接收客户端连接实现voidWebSocketServer::StartAccept(){// 创建新的连接对象每个客户端对应一个独立连接对象autocon_ptrstd::make_sharedConnection(_ioc);// 异步接收TCP连接回调处理连接结果_acceptor.async_accept(con_ptr-GetSocket(),[this,con_ptr](error_code err){try{// 接收连接成功if(!err){// 执行WebSocket握手升级连接con_ptr-AsyncAccept();}else{// 接收连接失败打印错误信息std::coutacceptor async_accept failed, err iserr.what()std::endl;}// 递归调用自身持续监听下一个客户端连接StartAccept();}catch(std::exceptionexp){// 捕获异常防止服务器崩溃std::coutasync_accept error is exp.what()std::endl;}});}八、beast_websocket.cpp程序主入口文件作用程序执行入口初始化IO上下文启动服务器运行事件循环#includeconst.h// 引入服务器核心类#includeWebSocketServer.hintmain(){// 创建Boost.Asio核心IO上下文负责所有异步事件调度net::io_context ioc;// 创建WebSocket服务器对象监听10086端口WebSocketServerserver(ioc,10086);// 启动服务器开始监听客户端连接server.StartAccept();// 运行IO上下文事件循环阻塞程序处理所有异步网络事件ioc.run();return0;}代码整体说明核心功能基于Boost.Beast实现WebSocket服务器监听10086端口接收客户端连接完成WebSocket握手实现消息回声接收客户端消息后原路返回支持多客户端同时连接设计模式单例模式连接管理器、智能指针管理对象生命周期、异步IO模型线程安全通过互斥锁保护消息队列strand保证异步回调单线程执行运行流程主函数启动→服务器监听端口→接收客户端TCP连接→升级为WebSocket连接→消息收发循环→连接断开后移除资源