一、const.h(全局头文件与命名空间定义)
作用:汇总项目所有依赖头文件,定义命名空间别名,防止头文件重复包含,作为项目基础头文件
cpp
#pragma once
// 防止头文件被重复包含,保证全局只引入一次
// 标准输入输出头文件,用于控制台日志打印
#include <iostream>
// Boost.Asio核心库,提供异步网络IO、套接字、事件循环支持
#include<boost/asio.hpp>
// Boost.Beast库,封装WebSocket/HTTP协议,实现WebSocket通信核心逻辑
#include<boost/beast.hpp>
// 内存操作相关头文件,项目预留使用
#include<memory.h>
// Boost UUID库,用于生成每个连接的唯一标识ID
#include<boost/uuid/uuid.hpp>
#include<boost/uuid/uuid_io.hpp>
#include<boost/uuid/uuid_generators.hpp>
// 队列容器,用于存储待发送的消息,保证消息顺序发送
#include<queue>
// 互斥锁,保证多线程环境下消息队列操作的线程安全
#include<mutex>
// 命名空间别名,简化代码书写,避免冗长的全命名空间写法
namespace net = boost::asio;
namespace beast = boost::beast;
// 直接引入WebSocket相关命名空间,方便直接调用相关类和函数
using namespace boost::beast;
using namespace boost::beast::websocket;
二、Connection.h(单个WebSocket连接类头文件)
作用:封装单个客户端WebSocket连接的所有功能,定义类成员变量和成员函数接口,继承智能指针相关类,解决异步回调生命周期问题
cpp
#pragma once
// 引入全局基础头文件
#include"const.h"
// 单个WebSocket连接处理类
// 继承std::enable_shared_from_this,用于在异步回调中获取自身的shared_ptr,防止对象提前销毁导致野指针
class Connection :public std::enable_shared_from_this<Connection>
{
public:
// 构造函数
// 参数:ioc - 异步IO上下文,引用传递,复用全局IO上下文
Connection(net::io_context& ioc);
// 获取当前连接的唯一UUID标识
std::string GetUid();
// 获取底层TCP套接字,供服务器监听端接收连接使用
net::ip::tcp::socket& GetSocket();
// 异步执行WebSocket握手,将TCP连接升级为WebSocket连接
void AsyncAccept();
// 启动连接,开始监听客户端消息,进入读写循环
void Start();
// 异步发送消息给客户端
// 参数:msg - 要发送的字符串消息
void AsyncSend(std::string msg);
private:
// WebSocket流对象,封装底层TCP流,unique_ptr保证独占所有权,禁止拷贝
std::unique_ptr<stream<tcp_stream>> _ws_ptr;
// 当前连接的唯一UUID字符串,用于连接管理和标识
std::string _uuids;
// 全局IO上下文引用,复用服务端事件循环
net::io_context& _ioc;
// 接收数据缓冲区,Beast提供的高效缓冲区,存储客户端发送的消息
flat_buffer _recv_buffer;
// 消息发送队列,缓存待发送消息,避免并发发送冲突
std::queue<std::string> _send_que;
// 发送队列互斥锁,保证多线程操作队列时的线程安全
std::mutex _send_mtx;
};
三、Connection.cpp(单个WebSocket连接类实现)
作用:实现Connection类的所有成员函数,处理WebSocket握手、消息读取、消息发送、连接维护等核心逻辑
cpp
#include "Connection.h"
// 引入连接管理器,用于注册和移除当前连接
#include"ConnectionMgr.h"
// 构造函数实现
// 初始化IO上下文引用,创建WebSocket流对象,生成唯一UUID
Connection::Connection(net::io_context& ioc)
: _ioc(ioc),
// 创建WebSocket流,绑定strand保证异步回调单线程执行,避免多线程冲突
_ws_ptr(std::make_unique<stream<tcp_stream>>(make_strand(ioc)))
{
// 创建UUID生成器,生成随机唯一ID
boost::uuids::random_generator generator;
boost::uuids::uuid uuid = generator();
// 将UUID转换为字符串,存储为当前连接标识
_uuids = boost::uuids::to_string(uuid);
}
// 获取当前连接唯一UUID的实现
std::string Connection::GetUid()
{
return _uuids;
}
// 获取底层TCP套接字实现
// 通过get_lowest_layer获取WebSocket流最底层的TCP套接字
net::ip::tcp::socket& Connection::GetSocket()
{
return boost::beast::get_lowest_layer(*_ws_ptr).socket();
}
// 异步WebSocket握手实现
// 等待客户端发起握手请求,完成协议升级
void Connection::AsyncAccept()
{
// 获取自身智能指针,保证异步回调期间对象不被销毁
auto self = shared_from_this();
// 异步接受WebSocket握手,回调函数处理握手结果
_ws_ptr->async_accept([self](boost::system::error_code err) {
try {
// 错误码为空,代表握手成功
if (!err)
{
// 将当前连接加入全局连接管理器,统一管理
ConnectionMgr::GetInstance().AddConnection(self);
// 握手成功,启动连接,开始监听消息
self->Start();
}
else
{
// 握手失败,打印错误信息
std::cout << "websocket accept failed, err is " << err.what() << std::endl;
}
}
catch (std::exception& exp)
{
// 捕获异常,防止程序崩溃,打印异常信息
std::cout << "websocket async accept exception is " << exp.what();
}
});
}
// 启动连接,进入消息读取循环
void Connection::Start()
{
// 获取自身智能指针
auto self = shared_from_this();
// 异步读取客户端发送的消息,数据存入接收缓冲区
_ws_ptr->async_read(_recv_buffer, [self](error_code err, size_t buffer_bytes) {
try {
// 读取出现错误,代表连接断开或异常
if (err)
{
std::cout << "websocket async read error is " << err.what();
// 从连接管理器移除当前连接,释放资源
ConnectionMgr::GetInstance().RmvConnection(self->GetUid());
return;
}
// 设置发送消息类型与客户端发送类型一致(文本/二进制)
self->_ws_ptr->text(self->_ws_ptr->got_text());
// 将缓冲区数据转换为字符串,方便处理
std::string recv_data = boost::beast::buffers_to_string(self->_recv_buffer.data());
// 清空接收缓冲区,准备下一次读取
self->_recv_buffer.consume(self->_recv_buffer.size());
// 打印接收到的客户端消息
std::cout << "websocket receive msg is " << recv_data << std::endl;
// 将接收到的消息回传给客户端(回声模式)
self->AsyncSend(std::move(recv_data));
// 递归调用Start,持续监听客户端后续消息
self->Start();
}
catch (std::exception& exp)
{
// 捕获异常,打印信息并移除连接
std::cout << "exception is " << exp.what() << std::endl;
ConnectionMgr::GetInstance().RmvConnection(self->GetUid());
}
});
}
// 异步发送消息实现
// 通过队列保证消息顺序发送,避免并发发送导致的问题
void Connection::AsyncSend(std::string msg)
{
{
// 加锁,保证队列操作的线程安全
std::lock_guard<std::mutex>lck_guard(_send_mtx);
// 获取当前队列长度
int que_len = _send_que.size();
// 将消息加入发送队列
_send_que.push(msg);
// 如果队列原本不为空,说明已有消息在发送,直接返回,等待上一条发送完成
if (que_len > 0)
{
return;
}
}
// 获取自身智能指针
auto self = shared_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::cout << "async_send err is" << err.what() << std::endl;
ConnectionMgr::GetInstance().RmvConnection(self->GetUid());
return;
}
std::string send_msg;
{
// 加锁操作发送队列
std::lock_guard<std::mutex> lck_gurad(self->_send_mtx);
// 移除已发送完成的消息
self->_send_que.pop();
// 队列为空,无后续消息,直接返回
if (self->_send_que.empty())
{
return;
}
// 获取队列中下一条待发送消息
send_msg = self->_send_que.front();
// 发送下一条消息
self->AsyncSend(std::move(send_msg));
}
}
catch (std::exception& exp)
{
// 捕获异常,处理连接
std::cout << "exception is " << exp.what() << std::endl;
ConnectionMgr::GetInstance().RmvConnection(self->GetUid());
}
});
}
四、ConnectionMgr.h(连接管理器头文件)
作用:单例模式实现全局连接管理器,统一管理所有客户端连接,提供添加、移除连接接口
cpp
#pragma once
// 引入全局头文件
#include"const.h"
// Boost无序哈希表,用于存储连接,查询效率更高
#include"boost/unordered_map.hpp"
// 引入连接类
#include "Connection.h"
// 连接管理类,采用单例模式,全局唯一
class ConnectionMgr
{
public:
// 获取单例实例,静态局部变量实现,线程安全
static ConnectionMgr& GetInstance();
// 添加新连接到管理器
// 参数:conptr - 连接对象的智能指针
void AddConnection(std::shared_ptr<Connection>conptr);
// 根据UUID移除连接
// 参数:id - 连接的唯一UUID
void RmvConnection(std::string);
public:
// 禁用拷贝构造函数,防止单例被拷贝
ConnectionMgr(const ConnectionMgr&) = delete;
// 禁用赋值运算符,保证单例唯一性
ConnectionMgr& operator = (const ConnectionMgr&) = delete;
// 构造函数私有化,禁止外部创建实例
ConnectionMgr();
// 存储所有活跃连接,key为UUID,value为连接智能指针
boost::unordered_map<std::string, std::shared_ptr<Connection>> _map_cons;
};
五、ConnectionMgr.cpp(连接管理器实现)
作用:实现单例连接管理器的具体功能,完成连接的添加、移除操作
cpp
#include "ConnectionMgr.h"
// 获取单例实例实现
// 静态局部变量在程序运行期间只初始化一次,保证全局唯一
ConnectionMgr& ConnectionMgr::GetInstance()
{
static ConnectionMgr instance;
return instance;
}
// 添加连接实现
// 将连接的UUID作为键,智能指针作为值存入哈希表
void ConnectionMgr::AddConnection(std::shared_ptr<Connection> conptr)
{
_map_cons[conptr->GetUid()] = conptr;
}
// 移除连接实现
// 根据UUID删除哈希表中对应的连接项
void ConnectionMgr::RmvConnection(std::string id)
{
_map_cons.erase(id);
}
// 构造函数实现,空实现
ConnectionMgr::ConnectionMgr()
{
}
六、WebSocketServer.h(服务器核心类头文件)
作用:定义WebSocket服务器核心类,负责监听端口、异步接收客户端TCP连接
cpp
#pragma once
// 引入全局头文件
#include"const.h"
// 引入连接管理器
#include"ConnectionMgr.h"
// WebSocket服务器核心类
class WebSocketServer
{
public:
// 禁用拷贝构造,防止服务器对象被拷贝
WebSocketServer(const WebSocketServer&) = delete;
// 禁用赋值运算符
WebSocketServer& operator = (const WebSocketServer&) = delete;
// 构造函数
// 参数:ioc - 全局IO上下文;port - 服务器监听端口
WebSocketServer(net::io_context& ioc, unsigned short port);
// 开始异步监听客户端连接
void StartAccept();
private:
// TCP接收器,负责监听端口,接收客户端TCP连接
net::ip::tcp::acceptor _acceptor;
// 全局IO上下文引用
net::io_context& _ioc;
};
七、WebSocketServer.cpp(服务器核心类实现)
作用:实现服务器监听、接收客户端连接的逻辑,循环接收新连接,分配给对应连接对象处理
cpp
#include "WebSocketServer.h"
// 构造函数实现
// 初始化接收器,绑定指定端口,监听所有网卡
WebSocketServer::WebSocketServer(net::io_context& ioc, unsigned short port)
:_ioc(ioc),
// 绑定IPv4地址和指定端口,开启监听
_acceptor(ioc, net::ip::tcp::endpoint(net::ip::tcp::v4(), port))
{
// 打印服务器启动信息,显示监听端口
std::cout << "Server start on port :" << port << std::endl;
}
// 开始接收客户端连接实现
void WebSocketServer::StartAccept()
{
// 创建新的连接对象,每个客户端对应一个独立连接对象
auto con_ptr = std::make_shared<Connection>(_ioc);
// 异步接收TCP连接,回调处理连接结果
_acceptor.async_accept(con_ptr->GetSocket(), [this, con_ptr](error_code err) {
try {
// 接收连接成功
if (!err)
{
// 执行WebSocket握手,升级连接
con_ptr->AsyncAccept();
}
else
{
// 接收连接失败,打印错误信息
std::cout << "acceptor async_accept failed, err is" << err.what() << std::endl;
}
// 递归调用自身,持续监听下一个客户端连接
StartAccept();
}
catch (std::exception& exp)
{
// 捕获异常,防止服务器崩溃
std::cout << "async_accept error is " << exp.what() << std::endl;
}
});
}
八、beast_websocket.cpp(程序主入口文件)
作用:程序执行入口,初始化IO上下文,启动服务器,运行事件循环
cpp
#include"const.h"
// 引入服务器核心类
#include"WebSocketServer.h"
int main()
{
// 创建Boost.Asio核心IO上下文,负责所有异步事件调度
net::io_context ioc;
// 创建WebSocket服务器对象,监听10086端口
WebSocketServer server(ioc, 10086);
// 启动服务器,开始监听客户端连接
server.StartAccept();
// 运行IO上下文事件循环,阻塞程序,处理所有异步网络事件
ioc.run();
return 0;
}
代码整体说明
-
核心功能:基于Boost.Beast实现WebSocket服务器,监听10086端口,接收客户端连接,完成WebSocket握手,实现消息回声(接收客户端消息后原路返回),支持多客户端同时连接
-
设计模式:单例模式(连接管理器)、智能指针管理对象生命周期、异步IO模型
-
线程安全:通过互斥锁保护消息队列,strand保证异步回调单线程执行
-
运行流程:主函数启动→服务器监听端口→接收客户端TCP连接→升级为WebSocket连接→消息收发循环→连接断开后移除资源