C++ 使用asio協(xié)程搭建異步服務(wù)器的過(guò)程
協(xié)程核心定義
協(xié)程是用戶態(tài)輕量級(jí)執(zhí)行單元,能在執(zhí)行中主動(dòng)暫停(掛起)并保留上下文,待條件滿足后恢復(fù)執(zhí)行,切換開(kāi)銷(xiāo)遠(yuǎn)低于線程;在你的Boost.Asio代碼中,協(xié)程通過(guò)co_await等待異步IO(如讀取客戶端數(shù)據(jù)),掛起時(shí)不阻塞線程,IO完成后自動(dòng)恢復(fù),讓異步代碼像同步代碼一樣易讀。
實(shí)現(xiàn):
#include <iostream>
// 引入Boost.Asio協(xié)程相關(guān)頭文件
#include<boost/asio/co_spawn.hpp> // 協(xié)程創(chuàng)建函數(shù)
#include<boost/asio/detached.hpp> // 協(xié)程分離執(zhí)行標(biāo)識(shí)
#include<boost/asio/io_context.hpp> // IO上下文(事件循環(huán))
#include<boost/asio/ip/tcp.hpp> // TCP相關(guān)功能
#include<boost/asio/signal_set.hpp> // 信號(hào)處理
#include<boost/asio/write.hpp> // 異步寫(xiě)操作
// 簡(jiǎn)化常用的Boost.Asio協(xié)程相關(guān)類(lèi)型/函數(shù)名
using boost::asio::ip::tcp;
using boost::asio::awaitable; // 協(xié)程返回類(lèi)型
using boost::asio::co_spawn; // 啟動(dòng)協(xié)程的函數(shù)
using boost::asio::detached; // 協(xié)程分離執(zhí)行(不等待完成)
using boost::asio::use_awaitable;// 異步操作適配協(xié)程的等待令牌
// 協(xié)程本地上下文命名空間別名,用于獲取當(dāng)前協(xié)程的執(zhí)行器
namespace this_coro = boost::asio::this_coro;
// 協(xié)程函數(shù):處理單個(gè)客戶端的回顯邏輯
// 參數(shù):已連接的TCP套接字(通過(guò)移動(dòng)語(yǔ)義傳遞,避免拷貝)
// 返回值:awaitable<void> 表示這是一個(gè)可等待的協(xié)程任務(wù)
awaitable<void>echo(tcp::socket socket)
{
try {
char data[1024]; // 數(shù)據(jù)接收緩沖區(qū),大小1024字節(jié)
// 無(wú)限循環(huán)處理客戶端數(shù)據(jù),直到連接斷開(kāi)/異常
for (;;)
{
// 異步讀取客戶端發(fā)送的數(shù)據(jù),協(xié)程掛起等待數(shù)據(jù)到達(dá)
// co_await:等待異步操作完成,期間不阻塞線程
// async_read_some:讀取任意長(zhǎng)度的數(shù)據(jù)到緩沖區(qū),返回實(shí)際讀取的字節(jié)數(shù)
std:: size_t n = co_await socket.async_read_some(boost::asio::buffer(data), use_awaitable);
// 異步將讀取到的數(shù)據(jù)原樣回寫(xiě)給客戶端,同樣通過(guò)co_await等待寫(xiě)完成
co_await async_write(socket, boost::asio::buffer(data, n), use_awaitable);
}
}
catch (std::exception& e)
{
// 捕獲連接斷開(kāi)、網(wǎng)絡(luò)異常等錯(cuò)誤,打印異常信息
std::cout << "回顯協(xié)程異常: " << e.what() << std::endl;
}
}
// 協(xié)程函數(shù):TCP服務(wù)器監(jiān)聽(tīng)邏輯,等待客戶端連接
awaitable<void>listener()
{
// 獲取當(dāng)前協(xié)程綁定的執(zhí)行器(調(diào)度器),用于后續(xù)創(chuàng)建接收器/套接字
auto executor = co_await this_coro::executor;
// 創(chuàng)建TCP接收器,綁定到指定執(zhí)行器,監(jiān)聽(tīng)I(yíng)Pv4的10086端口
tcp::acceptor acceptor(executor, { tcp::v4(), 10086 });
// 無(wú)限循環(huán)等待客戶端連接
for (;;)
{
// 異步等待客戶端接入,協(xié)程掛起,有新連接時(shí)返回已連接的套接字
tcp::socket socket = co_await acceptor.async_accept(use_awaitable);
// 啟動(dòng)新的協(xié)程處理該客戶端的回顯邏輯
// detached:新協(xié)程獨(dú)立執(zhí)行,不阻塞當(dāng)前監(jiān)聽(tīng)協(xié)程
// std::move:轉(zhuǎn)移套接字所有權(quán)到echo協(xié)程
co_spawn(executor, echo(std::move(socket)), detached);
}
}
int main()
{
try {
// 創(chuàng)建IO上下文,參數(shù)1表示用1個(gè)線程運(yùn)行事件循環(huán)
boost::asio::io_context io_context(1);
// 定義信號(hào)集,監(jiān)聽(tīng)SIGINT(Ctrl+C)和SIGTERM(進(jìn)程終止)信號(hào)
boost::asio::signal_set signals(io_context, SIGINT, SIGTERM);
// 異步等待信號(hào)觸發(fā),收到信號(hào)后停止IO上下文,優(yōu)雅退出程序
signals.async_wait([&](auto, auto)
{
io_context.stop();
});
// 啟動(dòng)監(jiān)聽(tīng)協(xié)程,detached表示協(xié)程后臺(tái)運(yùn)行,不阻塞main函數(shù)
co_spawn(io_context, listener(), detached);
// 運(yùn)行IO上下文的事件循環(huán),處理所有異步操作和協(xié)程任務(wù)
io_context.run();
}
catch (std::exception& e)
{
// 捕獲服務(wù)器啟動(dòng)階段的異常(如端口被占用),打印錯(cuò)誤信息
std::cout << "主程序異常: " << e.what() << std::endl;
}
return 0;
}
總結(jié)
- 協(xié)程核心特性:可暫停、可恢復(fù)、用戶態(tài)調(diào)度、低開(kāi)銷(xiāo)。
- 代碼中體現(xiàn):
awaitable標(biāo)記協(xié)程函數(shù),co_await實(shí)現(xiàn)掛起等待,依托io_context完成調(diào)度。 - 核心價(jià)值:用同步寫(xiě)法實(shí)現(xiàn)異步IO,避免回調(diào)嵌套,提升代碼可讀性和并發(fā)效率。
到此這篇關(guān)于C++ 使用asio協(xié)程搭建異步服務(wù)器的過(guò)程的文章就介紹到這了,更多相關(guān)C++ asio協(xié)程搭建異步服務(wù)器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語(yǔ)言數(shù)組學(xué)習(xí)之特殊矩陣的壓縮存儲(chǔ)
矩陣在計(jì)算機(jī)圖形學(xué)、工程計(jì)算中都占有舉足輕重的地位,本文將討論如何將矩陣更有效地存儲(chǔ)在內(nèi)存中,并且能夠方便地提取矩陣中的元素。感興趣的同學(xué)可以了解一下2021-12-12
Win11+?VS2022編譯?FFmpeg6.0?靜態(tài)庫(kù)的詳細(xì)過(guò)程
這篇文章主要介紹了Win11+VS2022編譯FFmpeg6.0靜態(tài)庫(kù)的方法,本文通過(guò)圖文實(shí)例代碼相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-08-08
c語(yǔ)言程序設(shè)計(jì)文件操作方法示例(CreateFile和fopen)
c主要的文件操作函數(shù)有:CreateFile,CloseHandle,ReadFile,WriteFile,SetFilePointer,GetFileSize。其中的讀寫(xiě)操作是以字符為單位,獲得文件大小也是以字符為單位。2013-12-12
C語(yǔ)言實(shí)現(xiàn)計(jì)算雙色球的中獎(jiǎng)率
這篇文章主要為大家詳細(xì)介紹了如何利用C語(yǔ)言實(shí)現(xiàn)計(jì)算雙色球的中獎(jiǎng)率,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-12-12
C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)易通訊錄功能
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)易通訊錄功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-06-06
C++實(shí)現(xiàn)RSA加密解密算法是示例代碼
非對(duì)稱(chēng)加密方式可以使通信雙方無(wú)需事先交換密鑰就可以建立安全通信,因此被廣泛應(yīng)用于身份認(rèn)證、數(shù)字簽名、等信息交換領(lǐng)域。其中最具有代表性的非對(duì)稱(chēng)加密方式就是RSA公鑰密碼體制。本文將用C++實(shí)現(xiàn)RSA加密解密算法,需要的可以參考一下2022-09-09

