0

0

如何使用Boost.Asio库进行c++网络编程? (异步TCP服务器)

穿越時空

穿越時空

发布时间:2026-01-15 12:41:03

|

194人浏览过

|

来源于php中文网

原创

不能直接用 io_context::run() 启动异步服务器,因为它是阻塞调用且仅在任务队列为空时退出,而服务器需持续接受连接;单线程 run() 易被耗时 handler 卡住,应多线程调用 run() 并用 shared_ptr 管理 session 生命周期、成员变量存储读缓冲、shared_ptr 包装写缓冲以确保内存安全。

如何使用boost.asio库进行c++网络编程? (异步tcp服务器)

为什么不能直接用 io_context::run() 启动异步服务器

因为 io_context::run() 是阻塞调用,且只在任务队列为空时才退出——而服务器需要持续接受新连接,必须保持 io_context 活跃。如果只调一个线程调用 run(),一旦某个 handler 耗时过长(比如同步磁盘 I/O),整个事件循环就卡住。

  • 正确做法是提前调用 io_context::post()io_context::dispatch() 注入 accept 循环起点
  • 推荐启动多个线程调用 run(),例如 std::thread{[&ctx]{ ctx.run(); }},避免单点阻塞
  • 注意:io_context 本身是线程安全的,但 handler 内部访问的共享资源(如连接列表)仍需加锁或用 strand

如何正确实现 accept 循环并避免重复监听

常见错误是每次 accept 完成后,忘记重新调用 acceptor.async_accept(),导致服务器只能处理一个连接就停止响应。

  • 必须在每个 async_accept 的 completion handler 末尾,再次发起下一轮 async_accept
  • 不要在构造 tcp::acceptor 后只调一次 async_accept
  • 推荐封装为成员函数(如 do_accept()),并在 handler 中递归调用自身
  • 监听 socket 需设置 reuse_address 选项,否则重启服务时可能报 Address already in use
acceptor_.open(tcp::v4());
acceptor_.set_option(tcp::socket::reuse_address(true));
acceptor_.bind({tcp::v4(), port_});
acceptor_.listen();
do_accept(); // 启动第一轮

怎么管理多个 client socket 的生命周期

裸指针或对象传给异步 handler 极易引发 use-after-free:handler 执行时,对应对象可能已被析构。

  • 必须用 std::shared_ptr 包裹每个连接会话对象
  • async_accept handler 中创建 shared_ptr,再把该指针传给后续所有 handler(包括 async_readasync_write
  • session 对象内部持有 tcp::socketio_context::strand(可选),确保回调串行执行
  • 关闭连接时调 socket_.close() 并清空 shared_ptr 引用,让内存自动回收

异步读写时 buffer 怎么传才安全

Boost.Asio 不复制 buffer 内容,而是保存其地址和长度供底层使用。若传入栈变量地址(如 std::array buf),handler 执行时该变量早已销毁。

先见AI
先见AI

数据为基,先见未见

下载

立即学习C++免费学习笔记(深入)”;

  • 读 buffer 必须是 session 对象的成员变量(如 std::array read_buffer_
  • 写 buffer 推荐用 std::shared_ptr<:vector>>,在 write handler 触发前确保它不被释放
  • 切勿在 lambda 中捕获局部 buffer 变量([buf] { ... }),应捕获 shared_from_this() 后访问成员
  • 使用 boost::asio::buffer(buf_, size) 包装,而非裸指针 + 长度

最易被忽略的是:即使用了 strand,也不能绕过 buffer 生命周期检查——strand 只保顺序,不保内存存活。

相关专题

更多
session失效的原因
session失效的原因

session失效的原因有会话超时、会话数量限制、会话完整性检查、服务器重启、浏览器或设备问题等等。详细介绍:1、会话超时:服务器为Session设置了一个默认的超时时间,当用户在一段时间内没有与服务器交互时,Session将自动失效;2、会话数量限制:服务器为每个用户的Session数量设置了一个限制,当用户创建的Session数量超过这个限制时,最新的会覆盖最早的等等。

307

2023.10.17

session失效解决方法
session失效解决方法

session失效通常是由于 session 的生存时间过期或者服务器关闭导致的。其解决办法:1、延长session的生存时间;2、使用持久化存储;3、使用cookie;4、异步更新session;5、使用会话管理中间件。

735

2023.10.18

cookie与session的区别
cookie与session的区别

本专题整合了cookie与session的区别和使用方法等相关内容,阅读专题下面的文章了解更详细的内容。

88

2025.08.19

lambda表达式
lambda表达式

Lambda表达式是一种匿名函数的简洁表示方式,它可以在需要函数作为参数的地方使用,并提供了一种更简洁、更灵活的编码方式,其语法为“lambda 参数列表: 表达式”,参数列表是函数的参数,可以包含一个或多个参数,用逗号分隔,表达式是函数的执行体,用于定义函数的具体操作。本专题为大家提供lambda表达式相关的文章、下载、课程内容,供大家免费下载体验。

204

2023.09.15

python lambda函数
python lambda函数

本专题整合了python lambda函数用法详解,阅读专题下面的文章了解更多详细内容。

190

2025.11.08

Python lambda详解
Python lambda详解

本专题整合了Python lambda函数相关教程,阅读下面的文章了解更多详细内容。

47

2026.01.05

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

388

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

571

2023.08.10

Golang gRPC 服务开发与Protobuf实战
Golang gRPC 服务开发与Protobuf实战

本专题系统讲解 Golang 在 gRPC 服务开发中的完整实践,涵盖 Protobuf 定义与代码生成、gRPC 服务端与客户端实现、流式 RPC(Unary/Server/Client/Bidirectional)、错误处理、拦截器、中间件以及与 HTTP/REST 的对接方案。通过实际案例,帮助学习者掌握 使用 Go 构建高性能、强类型、可扩展的 RPC 服务体系,适用于微服务与内部系统通信场景。

8

2026.01.15

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Laravel 5.8 中文文档手册
Laravel 5.8 中文文档手册

共74课时 | 84.7万人学习

SESSION实现登录与验证
SESSION实现登录与验证

共10课时 | 9.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号