0

0

c++如何实现一个简单的协程网络库_c++ C++20 coroutine与asio结合【实战】

冰火之心

冰火之心

发布时间:2025-12-25 18:13:29

|

386人浏览过

|

来源于php中文网

原创

C++20协程+Asio可实现直观同步风格的网络库:通过use_awaitable直接co_await异步操作;用when_all组合connect与超时;session协程自动管理生命周期;co_spawn驱动accept循环,无需回调嵌套。

c++如何实现一个简单的协程网络库_c++ c++20 coroutine与asio结合【实战】

用 C++20 协程 + Asio 实现一个轻量协程网络库,核心不是“造轮子”,而是把 co_await 和 Asio 的异步操作自然衔接起来,让 TCP 连接、读写、超时等逻辑写得像同步代码一样直观。

1. 基础:把 asio 的 async_xxx 封装成可 co_await 的 awaitable

Asio 本身不直接返回 awaitable,但提供了 use_awaitable 令牌(C++20 模式下需启用 ASIO_ENABLE_BOOST_BIND_HPP 或使用 Asio 1.28+ 的原生协程支持)。最简封装方式是:

✅ 推荐做法(Asio ≥ 1.26,启用 ASIO_ENABLE_COROUTINES):

  • 在编译时定义 ASIO_ENABLE_COROUTINES(或用 asio::use_awaitable
  • 所有支持 async 的对象(如 tcp::socket, steady_timer)可直接 co_await socket.async_read_some(..., use_awaitable)
  • 无需手写 await_suspend/await_resume,Asio 内部已实现

⚠️ 注意:确保 io_context 运行在支持协程的线程中(比如用 co_spawn 启动协程)。

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

2. 写一个协程化的 TCP 连接器(connect_with_timeout)

这是典型场景:连接带超时,失败/超时都统一处理,不用回调嵌套。

示例代码结构:

超会AI
超会AI

AI驱动的爆款内容制造机

下载
task connect_with_timeout(
    tcp::socket& sock,
    const tcp::endpoint& ep,
    std::chrono::milliseconds timeout_ms) {
  auto ex = sock.get_executor();
  steady_timer timer{ex, timeout_ms};

  // 并发等待 connect 或 timer
  auto [ec1, ec2] = co_await when_all(
      [&]()->task {
        co_return co_await sock.async_connect(ep, use_awaitable);
      }(),
      [&]()->task {
        co_await timer.async_wait(use_awaitable);
        co_return make_error_code(errc::timed_out);
      }()
  );

  if (!ec1) co_return ec1;  // connect 成功
  if (!ec2) {               // timer 触发,主动关闭 socket
    boost::system::error_code ignored;
    sock.close(ignored);
    co_return ec2;
  }
  co_return ec1 ? ec1 : ec2;
}

? 关键点:when_all 是 Asio 提供的协程组合子(需 #include ),类似 Go 的 select。

3. 协程化会话(session):读-处理-写的闭环

每个连接启动一个协程,生命周期清晰,错误可自然传播:

task session(tcp::socket sock) {
  try {
    char buf[1024];
    for (;;) {
      auto [ec, n] = co_await sock.async_read_some(
          asio::buffer(buf), use_awaitable);
      if (ec == asio::error::eof) break;
      if (ec) throw std::system_error{ec};

      // 处理请求(例如 echo)
      auto [wec, wn] = co_await sock.async_write_some(
          asio::buffer(buf, n), use_awaitable);
      if (wec) throw std::system_error{wec};
    }
  } catch (const std::exception& e) {
    // 自动清理:sock 离开作用域自动关闭
  }
}

✅ 优势:无手动资源管理、无状态机、异常即断连、语义清晰。

4. 启动服务:accept 循环用 co_spawn 驱动

避免阻塞主线程,也不用 while+poll,用协程“挂起等待”新连接:

task server_loop(tcp::acceptor& acceptor) {
  for (;;) {
    tcp::socket sock{acceptor.get_executor()};
    auto [ec] = co_await acceptor.async_accept(sock, use_awaitable);
    if (ec) continue;

    // 每个连接派生独立协程,不阻塞 accept 循环
    co_spawn(acceptor.get_executor(),
        [=]() mutable -> task { co_await session(std::move(sock)); },
        detached);
  }
}

// 启动入口
int main() {
  asio::io_context ioc;
  tcp::acceptor acceptor{ioc, {tcp::v4(), 8080}};
  
  co_spawn(ioc, [&]()->task { co_await server_loop(acceptor); }, detached);
  ioc.run();
}

? 提示:生产环境建议加连接数限制、缓冲区复用、日志和错误监控,但骨架已具备可维护性。

基本上就这些——没有宏魔法,不依赖第三方协程调度器,纯 Asio + C++20 标准特性。难点不在语法,而在理解 executor 绑定、协程生命周期与 io_context 的协作关系。写熟几个 awaitable 封装后,网络逻辑反而比传统回调更直白。

相关专题

更多
while的用法
while的用法

while的用法是“while 条件: 代码块”,条件是一个表达式,当条件为真时,执行代码块,然后再次判断条件是否为真,如果为真则继续执行代码块,直到条件为假为止。本专题为大家提供while相关的文章、下载、课程内容,供大家免费下载体验。

79

2023.09.25

session失效的原因
session失效的原因

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

301

2023.10.17

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

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

700

2023.10.18

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

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

86

2025.08.19

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

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

359

2023.07.18

堆和栈区别
堆和栈区别

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

558

2023.08.10

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

462

2023.08.10

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

462

2023.08.10

笔记本电脑卡反应很慢处理方法汇总
笔记本电脑卡反应很慢处理方法汇总

本专题整合了笔记本电脑卡反应慢解决方法,阅读专题下面的文章了解更多详细内容。

1

2025.12.25

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Go 教程
Go 教程

共32课时 | 2.9万人学习

Go语言实战之 GraphQL
Go语言实战之 GraphQL

共10课时 | 0.8万人学习

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

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