C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > C++ asio协程搭建异步服务器

C++ 使用asio协程搭建异步服务器的过程

作者:C++ 练习生

本文给大家介绍C++ 使用asio协程搭建异步服务器的过程,本文结合示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧

协程核心定义

协程是用户态轻量级执行单元,能在执行中主动暂停(挂起)并保留上下文,待条件满足后恢复执行,切换开销远低于线程;在你的Boost.Asio代码中,协程通过co_await等待异步IO(如读取客户端数据),挂起时不阻塞线程,IO完成后自动恢复,让异步代码像同步代码一样易读。

实现:

#include <iostream>
// 引入Boost.Asio协程相关头文件
#include<boost/asio/co_spawn.hpp>    // 协程创建函数
#include<boost/asio/detached.hpp>    // 协程分离执行标识
#include<boost/asio/io_context.hpp>  // IO上下文(事件循环)
#include<boost/asio/ip/tcp.hpp>      // TCP相关功能
#include<boost/asio/signal_set.hpp>  // 信号处理
#include<boost/asio/write.hpp>       // 异步写操作

// 简化常用的Boost.Asio协程相关类型/函数名
using boost::asio::ip::tcp;
using boost::asio::awaitable;   // 协程返回类型
using boost::asio::co_spawn;    // 启动协程的函数
using boost::asio::detached;    // 协程分离执行(不等待完成)
using boost::asio::use_awaitable;// 异步操作适配协程的等待令牌
// 协程本地上下文命名空间别名,用于获取当前协程的执行器
namespace this_coro = boost::asio::this_coro;

// 协程函数:处理单个客户端的回显逻辑
// 参数:已连接的TCP套接字(通过移动语义传递,避免拷贝)
// 返回值:awaitable<void> 表示这是一个可等待的协程任务
awaitable<void>echo(tcp::socket socket)
{
	try {
		char data[1024];  // 数据接收缓冲区,大小1024字节
		// 无限循环处理客户端数据,直到连接断开/异常
		for (;;)
		{
			// 异步读取客户端发送的数据,协程挂起等待数据到达
			// co_await:等待异步操作完成,期间不阻塞线程
			// async_read_some:读取任意长度的数据到缓冲区,返回实际读取的字节数
			std:: size_t n = co_await socket.async_read_some(boost::asio::buffer(data), use_awaitable);
			// 异步将读取到的数据原样回写给客户端,同样通过co_await等待写完成
			co_await async_write(socket, boost::asio::buffer(data, n), use_awaitable);
		}
	}
	catch (std::exception& e)
	{
		// 捕获连接断开、网络异常等错误,打印异常信息
		std::cout << "回显协程异常: " << e.what() << std::endl;
	}
}

// 协程函数:TCP服务器监听逻辑,等待客户端连接
awaitable<void>listener()
{
	// 获取当前协程绑定的执行器(调度器),用于后续创建接收器/套接字
	auto executor = co_await this_coro::executor;
	// 创建TCP接收器,绑定到指定执行器,监听IPv4的10086端口
	tcp::acceptor acceptor(executor, { tcp::v4(), 10086 });
	// 无限循环等待客户端连接
	for (;;)
	{
		// 异步等待客户端接入,协程挂起,有新连接时返回已连接的套接字
		tcp::socket socket = co_await acceptor.async_accept(use_awaitable);
		// 启动新的协程处理该客户端的回显逻辑
		// detached:新协程独立执行,不阻塞当前监听协程
		// std::move:转移套接字所有权到echo协程
		co_spawn(executor, echo(std::move(socket)), detached);
	}
}

int main()
{
	try {
		// 创建IO上下文,参数1表示用1个线程运行事件循环
		boost::asio::io_context io_context(1);
		// 定义信号集,监听SIGINT(Ctrl+C)和SIGTERM(进程终止)信号
		boost::asio::signal_set signals(io_context, SIGINT, SIGTERM);
		// 异步等待信号触发,收到信号后停止IO上下文,优雅退出程序
		signals.async_wait([&](auto, auto)
			{
				io_context.stop();
			});
		// 启动监听协程,detached表示协程后台运行,不阻塞main函数
		co_spawn(io_context, listener(), detached);

		// 运行IO上下文的事件循环,处理所有异步操作和协程任务
		io_context.run(); 
	}
	catch (std::exception& e)
	{
		// 捕获服务器启动阶段的异常(如端口被占用),打印错误信息
		std::cout << "主程序异常: " << e.what() << std::endl;
	}
	return 0;
}

总结

  1. 协程核心特性:可暂停、可恢复、用户态调度、低开销
  2. 代码中体现:awaitable标记协程函数,co_await实现挂起等待,依托io_context完成调度。
  3. 核心价值:用同步写法实现异步IO,避免回调嵌套,提升代码可读性和并发效率。

到此这篇关于C++ 使用asio协程搭建异步服务器的过程的文章就介绍到这了,更多相关C++ asio协程搭建异步服务器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文