協程驅動的高性能異步 HTTP 服務器:基礎實現與任務調度機制

一、引言:為什么用協程實現 HTTP 服務器?

傳統 HTTP 服務器的編程模型大致分為:

  • 多線程阻塞型:每連接一線程,簡潔但擴展性差

  • 事件驅動模型(如 epoll + 狀態機):高性能但邏輯復雜

  • 回調式異步(如 Boost::Asio):性能好但寫法晦澀

C++20 引入 原生協程(coroutine) 后,我們可以用“同步風格”編寫異步邏輯,兼顧性能與可讀性。

本文將帶你從零實現一個基于協程 + epoll 的輕量 HTTP 服務器,支持多連接并發、非阻塞 I/O 以及協程調度。


二、項目目標與能力規劃

項目目標

實現一個簡易 HTTP 服務:

  • 使用 epoll 管理連接

  • 每個連接由一個協程處理

  • 實現 HTTP 請求解析 + 回應

  • 支持并發數千連接的負載能力


三、項目結構概覽

 

swift

復制編輯

/http_coro_server/ │ ├── main.cpp // 主程序,啟動監聽與事件循環 ├── coroutine_task.hpp // Task 協程封裝 ├── epoll_loop.hpp // epoll 封裝與事件調度 ├── connection.hpp // 每個連接處理邏輯(協程) └── utils.hpp // socket/非阻塞工具函數


四、基礎組件 1:協程返回類型 Task

 

cpp

復制編輯

// coroutine_task.hpp template<typename T = void> struct Task { struct promise_type { std::optional<T> value; Task get_return_object() { return Task{std::coroutine_handle<promise_type>::from_promise(*this)}; } std::suspend_always initial_suspend() noexcept { return {}; } std::suspend_always final_suspend() noexcept { return {}; } void return_value(T v) { value = v; } void unhandled_exception() { std::exit(1); } }; std::coroutine_handle<promise_type> handle; Task(std::coroutine_handle<promise_type> h) : handle(h) {} ~Task() { if (handle) handle.destroy(); } void start() { handle.resume(); } };


五、基礎組件 2:設置非阻塞 socket 工具

 

cpp

復制編輯

// utils.hpp int set_non_blocking(int fd) { int flags = fcntl(fd, F_GETFL, 0); return fcntl(fd, F_SETFL, flags | O_NONBLOCK); } int create_server_socket(int port) { int fd = socket(AF_INET, SOCK_STREAM, 0); sockaddr_in addr{AF_INET, htons(port), INADDR_ANY}; bind(fd, (sockaddr*)&addr, sizeof(addr)); listen(fd, SOMAXCONN); set_non_blocking(fd); return fd; }


六、基礎組件 3:epoll 封裝與事件管理

 

cpp

復制編輯

// epoll_loop.hpp class EpollLoop { int epoll_fd; std::unordered_map<int, std::coroutine_handle<>> waiters; public: EpollLoop() { epoll_fd = epoll_create1(0); } void add(int fd, uint32_t events, std::coroutine_handle<> h) { epoll_event ev{events, {.fd = fd}}; epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev); waiters[fd] = h; } void resume_events() { epoll_event events[64]; int n = epoll_wait(epoll_fd, events, 64, 10); for (int i = 0; i < n; ++i) { int fd = events[i].data.fd; if (waiters.count(fd)) { auto h = waiters[fd]; waiters.erase(fd); h.resume(); } } } void remove(int fd) { epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, nullptr); waiters.erase(fd); } };


七、Awaitable 類型封裝:ReadAwaiter / WriteAwaiter

 

cpp

復制編輯

struct ReadAwaiter { int fd; EpollLoop& loop; bool await_ready() { return false; } void await_suspend(std::coroutine_handle<> h) { loop.add(fd, EPOLLIN | EPOLLET, h); } void await_resume() {} }; struct WriteAwaiter { int fd; EpollLoop& loop; bool await_ready() { return false; } void await_suspend(std::coroutine_handle<> h) { loop.add(fd, EPOLLOUT | EPOLLET, h); } void await_resume() {} };


八、協程:每個連接的處理邏輯

 

cpp

復制編輯

// connection.hpp Task<> handle_connection(int client_fd, EpollLoop& loop) { char buf[1024]; std::string request; while (true) { co_await ReadAwaiter{client_fd, loop}; int n = read(client_fd, buf, sizeof(buf)); if (n <= 0) break; request.append(buf, n); if (request.find("\r\n\r\n") != std::string::npos) break; } std::string response = "HTTP/1.1 200 OK\r\n" "Content-Length: 13\r\n" "Content-Type: text/plain\r\n\r\n" "Hello, world!"; co_await WriteAwaiter{client_fd, loop}; send(client_fd, response.c_str(), response.size(), 0); close(client_fd); }


九、main 函數:接受連接 + 事件循環

 

cpp

復制編輯

// main.cpp #include "coroutine_task.hpp" #include "utils.hpp" #include "epoll_loop.hpp" #include "connection.hpp" int main() { int server_fd = create_server_socket(8080); EpollLoop loop; while (true) { sockaddr_in client_addr; socklen_t len = sizeof(client_addr); int client_fd = accept(server_fd, (sockaddr*)&client_addr, &len); if (client_fd >= 0) { set_non_blocking(client_fd); handle_connection(client_fd, loop).start(); } loop.resume_events(); // 激活等待事件的協程 } close(server_fd); }


十、性能測試建議

可以使用 Apache Benchmark 或 wrk 進行測試:

 

bash

復制編輯

ab -n 10000 -c 100 http://127.0.0.1:8080/

或:

 

bash

復制編輯

wrk -t4 -c100 -d10s http://localhost:8080/


十一、可拓展方向

功能描述
路由系統根據 path 分發協程函數處理
支持 POST / JSON 請求使用簡單 parser 解析請求體
Keep-Alive / 連接復用支持復用 client_fd 管理多個請求
異步文件讀取結合協程讀取 HTML/文件資源
TLS/SSL 支持整合 OpenSSL,使用協程方式發送加密響應


十二、項目優勢與可落地性

  • C++20 原生協程,無需 Boost、libuv 等繁重依賴

  • epoll + 協程方式性能優于線程池架構

  • 易于理解與拓展,可逐步演化為微型 Web 框架

  • 支持高并發請求處理,適合 IoT、嵌入式、微服務網關等場景


十三、總結

我們實現了一個完整的協程驅動 HTTP Server:

  • 基于 C++20 coroutine + epoll 構建事件驅動框架

  • 每個連接一個協程,邏輯清晰,處理自然

  • 使用 Awaitable 類型管理 I/O 阻塞

  • 實現非阻塞 accept、read、write

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/911806.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/911806.shtml
英文地址,請注明出處:http://en.pswp.cn/news/911806.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

《視頻:點亮數字時代的光影魔方》

視頻的前世今生&#xff1a;從誕生到爆火 視頻的發展歷程是一部充滿創新與變革的歷史&#xff0c;它見證了科技的飛速進步和人類對信息傳播與娛樂方式不斷追求的過程。從早期的雛形到如今的全面普及&#xff0c;視頻經歷了多個重要階段&#xff0c;每一個階段都伴隨著關鍵節點與…

秋招Day14 - MySQL - 運維

百萬級別以上的數據如何刪除&#xff1f; 這么大量的DELETE操作可能會導致長時間鎖表 可以進行批量刪除&#xff0c;把要刪除的數據分為多個小批次處理。 也可以采用創建新表&#xff0c;把不需要刪除的數據遷移過來&#xff0c;然后廢棄舊表。需要檢查新表空間是否足夠、分…

(C++)vector數組相關基礎用法(C++教程)(STL庫基礎教程)

源代碼&#xff1a; #include <iostream> #include <vector> #include <string> using namespace std;int main(){char a;int b;int c;vector <char> numbers;cout<<"請輸入一組字符&#xff08;按下#結束&#xff09;:\n";while(1){…

面試的問題

主題&#xff1a;LLM相關、多模態相關、python編程、java編程 參見&#xff1a;小紅書面試相關的帖子 LLM相關&#xff1a; 02.大語言模型架構/1.attention/1.attention.md qzl66/llm_interview_note - Gitee.com 02.大語言模型架構/Transformer架構細節/Transformer架構細…

【EDA軟件】【應用功能子模塊網表提供和加載編譯方法】

1.背景 使用者做FPGA應用開發&#xff0c;將開發成果交給自己的客戶&#xff0c;但是并不想提供RTL源碼以及加密的源碼&#xff0c;只想提供網表文件。 2.方法 2.1 指定應用功能子模塊設置為Top層&#xff1b; 2.2 運行綜合&#xff0c;在outputs文件夾下會生成該應用功能子…

Spring:多數據源配置多個事務管理器DEMO

Spring配置文件&#xff1a; 配置2個事務管理器&#xff1a;txManager和txManager2 <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/2001/XMLS…

通用 Excel 導出功能設計與實現:動態列選擇與靈活配置

在企業級應用開發中&#xff0c;數據導出是高頻需求。本文介紹一種支持動態列選擇、靈活配置的通用 Excel 導出方案&#xff0c;通過前后端協同設計&#xff0c;實現導出字段、列順序、數據格式的自定義&#xff0c;滿足多樣化業務場景。 一、功能架構設計 核心特性 動態字段…

安全壁壘 - K8s 的 RBAC、NetworkPolicy 與 SecurityContext 精要

安全壁壘 - K8s 的 RBAC、NetworkPolicy 與 SecurityContext 精要 如果說 Kubernetes 是我們構建云原生應用的“城市”,那么我們已經學會了如何規劃道路(網絡)、建設住宅(Pod 調度)、提供水電(存儲)以及智能調節城市規模(自動伸縮)。現在,是時候為這座城市安裝“城門…

服務器開放端口如何設置,本地內網開通應用端口讓外網訪問連接步驟

在互聯網時代&#xff0c;服務器扮演著至關重要的角色&#xff0c;為了讓本地搭建部署的服務器能夠正常提供互聯網服務&#xff0c;我們需要開放特定端口以供外部網絡的客戶端訪問&#xff0c;本文將帶領大家深入了解內網本地服務器如何設置端口開放給公網訪問。 服務器開放端…

【深度學習新浪潮】什么是上下文工程?

什么是上下文工程? 上下文工程(Context Engineering) 是指通過設計、優化與大語言模型(LLM)交互時的輸入內容(即“上下文”),引導模型生成更符合預期、更精準回答的系統性方法。這里的“上下文”通常包括 提示詞(Prompt)、示例(Few-Shot Examples)、歷史對話記錄、…

Ansible ad-hoc模式常用三大模塊“script、shell、command“應用筆記

script模塊 - 外賣廚師 相當于你把做好的菜譜&#xff08;腳本文件&#xff09;分發給別人廚房執行 適合場景&#xff1a; ? 需要復雜菜譜&#xff08;多步驟腳本&#xff09; ? 保證每家分店味道一致&#xff08;環境標準化&#xff09; 示例&#xff1a;把《紅燒肉制作指…

雙重檢查鎖定實現的單例模式為什么需要volatile

今天介紹一下 單例模式(Singleton) 應用場景&#xff1a;配置管理類、數據庫連接池、線程池 實現方式&#xff1a;雙重檢查鎖定、靜態內部類、枚舉 public class ConfigManager {private static volatile ConfigManager instance;private ConfigManager() {}public static C…

Flink流水線+Gravitino+Paimon集成

1.數據源管理 1.1 添加Gravitino數據源 添加成功之后&#xff0c;會在Gravitino中創建一個名為配置的中的meatalake 1.2. 添加Paimon數據源 屬性gravitinoId可以關聯前面創建的Gravitino數據源&#xff0c;關聯后&#xff0c;會在gravitino下創建一個該數據源的catalog。 2. …

關系代數詳解與SQL示例

關系代數詳解與SQL示例 關系代數是關系數據庫的理論基礎&#xff0c;它提供了一組操作符用于操作關系&#xff08;表&#xff09; 1. 基本操作 1.1 選擇 (Selection, σ) 選擇操作從關系中選擇滿足特定條件的元組&#xff08;行&#xff09;。 關系代數表示&#xff1a;σ條…

Android14音頻子系統-Linux音頻子系統ASoC-ALSA

文章目錄 1、術語2、概述1&#xff09;資料快車 3、預備工作1&#xff09;codec - UDA1340 - 硬件規格2&#xff09;ASOC-ALSA代碼重點目錄介紹3&#xff09;ASOC-ALSA層級介紹4&#xff09;了解基本的軟硬件架構 4、數據結構5、代碼分析1&#xff09;Machine1、總體流程介紹2、…

零基礎入門Java+大模型(持續更新)

0.初始一些常見的概念 AI&#xff1a;人工智能 大模型劃分&#xff1a;&#xff08;本章了解一下這個就行&#xff09;NLP模型-->自然語言模型&#xff08;AI現在爆火的原因&#xff0c;就是自然語言模型這一塊取得了很大的成就&#xff09;。 LLM&#xff1a;大語言模型…

數據庫系統總結

數據庫系統概述 數據庫系統&#xff08;Database System, DBS&#xff09;是用于高效管理、存儲和檢索數據的軟件系統。 數據庫系統的組成包括&#xff1a;數據庫、硬件、軟件、人員。 三級模式-兩級映像 內模式&#xff1a;管理如何存儲物理的數據&#xff0c;對數據的存儲…

2026-軟件工程-《軟件質量測試與保證》-期末復習—習題匯總

題量: 20 滿分: 100 作答時間:06-04 17:30至06-22 23:59 智能分析 80分 一. 單選題&#xff08;共10題&#xff0c;50分&#xff09; (單選題)白盒測試設計測試用例的依據是( )。 A. 代碼邏輯結構 B. 代碼注釋說明 C. 需求規格說明書 D. 用戶使用場景 我的答案:A:代碼邏輯結構…

量化面試綠皮書:35. 蒙蒂霍爾問題

文中內容僅限技術學習與代碼實踐參考&#xff0c;市場存在不確定性&#xff0c;技術分析需謹慎驗證&#xff0c;不構成任何投資建議。 35. 蒙蒂霍爾問題 蒙提霍爾問題是一個基于美國老電視節目《讓我們做個交易》的概率謎題&#xff0c;該問題以該節目的主持人命名。假設你現在…

如何防范 SQL 注入攻擊以及SQL 注入防范技巧

在互聯網高度發展的時代&#xff0c;網絡安全問題日益突出&#xff0c;SQL 注入攻擊成為眾多網站和應用程序面臨的嚴重威脅之一。本文將詳細介紹如何防范 SQL 注入攻擊&#xff0c;通過多個關鍵方面的詳細闡述&#xff0c;幫助開發者和網站管理者構建更安全的網絡環境&#xff…