基于Boost Beast实现多WebSocket满CPU占用的代码改造需求
需求与实现方案:多WebSocket连接占用近100% CPU示例
环境说明
- 系统:Linux Ubuntu 22.04
- 编译环境:C++20(cxxstd-2a)
- Boost版本:1.81.0(已完成编译,包含boost::beast组件)
- 现有代码:简单WebSocket客户端、advanced-server-flex-awaitable服务端
- 需求:修改代码实现多WebSocket连接占用近100% CPU的示例
现有运行命令
客户端运行命令
okatz@okatz2015:~/Public/boost/boost_1_81_0/bin.v2/libs/beast/example/websocket/client/awaitable/gcc-11/debug/cxxstd-2a-iso/threading-multi/visibility-hidden$ ./websocket-client-awaitable localhost 8080 "Hello, world!" Hello, world!
服务端运行命令
# 进程1 (pyjwt) okatz@okatz2015:~/Public/boost/boost_1_81_0$ ^C (pyjwt) okatz@okatz2015:~/Public/boost/boost_1_81_0$ sudo ./bin.v2/libs/beast/example/advanced/server-flex-awaitable/gcc-11/debug/cxxstd-2a-iso/threading-multi/visibility-hidden/advanced-server-flex-awaitable 0.0.0.0 8080 . 1 [sudo] password for okatz: ***** # 进程2 okatz@okatz2015:~/Public/boost/boost_1_81_0/bin.v2/libs/beast/example/websocket/client/awaitable/gcc-11/debug/cxxstd-2a-iso/threading-multi/visibility-hidden$ ./websocket-client-awaitable localhost 8080 "Hello, world!" Hello, world!
修改方案
服务端修改(advanced-server-flex-awaitable)
核心思路是让每个WebSocket连接在事件循环中持续执行CPU密集型任务,同时保持连接活跃,最大化CPU占用。
- 添加CPU密集任务到会话逻辑
在WebSocket会话的处理函数中,插入无限循环的无意义计算,占用CPU资源:
// 定义CPU密集型任务 asio::awaitable<void> cpu_bound_task() { while (true) { // 无意义浮点运算,持续占用CPU volatile double x = 1.0; for (int i = 0; i < 1000; ++i) { x = x * 1.0001 + sqrt(x); } // 短暂让出执行权,避免完全阻塞事件循环(可根据需求调整或移除) co_await boost::asio::post(boost::asio::use_awaitable); } } // 在会话启动函数中调用该任务 co_await cpu_bound_task();
- 调整服务端线程数
启动服务端时,指定与CPU核心数一致的线程数(替换原命令最后参数1为$(nproc)):
sudo ./advanced-server-flex-awaitable 0.0.0.0 8080 . $(nproc)
客户端修改
通过批量创建并发WebSocket连接,持续发送消息触发服务端的CPU密集任务。
- 修改客户端代码实现批量连接
新增连接数参数,循环创建多个异步WebSocket连接并持续发送消息:
int main(int argc, char** argv) { try { if (argc != 5) { std::cerr << "Usage: " << argv[0] << " <host> <port> <text> <connection-count>\n"; return 1; } auto const host = argv[1]; auto const port = argv[2]; auto const text = argv[3]; int const conn_count = std::stoi(argv[4]); boost::asio::io_context ioc; boost::asio::signal_set signals(ioc, SIGINT, SIGTERM); signals.async_wait([&](auto, auto){ ioc.stop(); }); // 批量创建WebSocket连接 for (int i = 0; i < conn_count; ++i) { boost::asio::co_spawn(ioc, run(ioc, host, port, text), boost::asio::detached); } ioc.run(); } catch (std::exception const& e) { std::cerr << "Error: " << e.what() << std::endl; return 1; } return 0; } // 修改run函数,持续发送消息 asio::awaitable<void> run(asio::io_context& ioc, std::string host, std::string port, std::string text) { try { tcp::resolver resolver(co_await asio::this_coro::executor); auto const results = resolver.resolve(host, port); websocket::stream<tcp::socket> ws(ioc); co_await ws.async_connect(results, asio::use_awaitable); // 持续发送消息,触发服务端CPU任务 while (true) { co_await ws.async_write(asio::buffer(text), asio::use_awaitable); beast::flat_buffer buffer; co_await ws.async_read(buffer, asio::use_awaitable); // 可选:添加短暂延迟,避免消息发送过快 co_await asio::steady_timer(ioc, std::chrono::milliseconds(10)).async_wait(asio::use_awaitable); } } catch (std::exception const& e) { std::cerr << "Connection error: " << e.what() << std::endl; } }
- 编译后运行客户端
指定足够多的连接数(例如CPU核心数的10倍):
./websocket-client-awaitable localhost 8080 "Ping" 80
验证CPU占用
启动服务端后运行客户端,使用top或htop命令查看进程CPU使用率,此时服务端进程的CPU占用应接近100%。
内容的提问来源于stack exchange,提问作者Ori Kovacsi-Katz
相关产品推荐
相关产品推荐

