积累沉淀

待山花烂漫,化茧成蝶

CoroNet高性能协成网络库

前言: 这是一个极具前瞻性和工程价值的目标!结合 C++20 协程Linux 的 io_uringWindows 的 IOCP,打造一个真正高性能、跨平台、同步风格编写、异步底层执行的网络库,正是现代系统编程的“圣杯”之一。


一、项目名称建议(简洁、有技术感、易记)

名称 含义/联想 推荐度
CoroNet Coroutine + Network,简洁直白 ⭐⭐⭐⭐⭐
UringIO 突出 io_uring,但弱化 Windows ⭐⭐
Asyncore Async + Core,类似 Python asyncio ⭐⭐⭐
NetFiber Fiber 风格协程 + Net ⭐⭐⭐
CoSocket 协程 Socket,直观 ⭐⭐⭐⭐
Aether “以太”,古希腊中传递信息的媒介,寓意轻盈、高速、无形 ⭐⭐⭐⭐⭐(文艺+技术感)
Strand 意为“线束”,隐喻协程流 + I/O 流 ⭐⭐⭐⭐

✅ 最终推荐:

CoroNet —— 简洁、明确、易拼写、域名可用(coronet.dev / .io),开发者一眼看懂用途。


二、架构设计思想(核心原则)

🎯 总目标:

“Write like sync, run like async — on any platform.”
(像写同步代码一样简单,像异步引擎一样高效——跨平台。)


1. 分层架构(Layered Design)

1
2
3
4
5
6
7
8
9
10
11
┌──────────────────────────────┐
│ User Application │ ← C++20 协程:co_await socket.recv()
├──────────────────────────────┤
│ CoroNet Runtime (Core) │ ← 协程调度器 + 跨平台抽象层
├──────────────────────────────┤
│ Platform Backend │
│ ┌─────────────┬──────────┐ │
│ │ Linux │ Windows │ │
│ │ io_uring │ IOCP │ │
│ └─────────────┴──────────┘ │
└──────────────────────────────┘

各层职责:

层级 职责
用户层 编写 co_await connect(), co_await send(), co_await recv(),无回调、无状态机
Runtime Core - 协程调度器(支持 work-stealing) - 统一 Awaitable 接口 - 超时、取消、错误传播机制
Platform Backend - Linux: 封装 io_uring 提交/完成 - Windows: 封装 WSARecv/WSASend + IOCP 完成队列 - 自动选择最优后端

2. 关键设计原则

✅ 原则 1:零抽象惩罚(Zero-overhead Abstraction)

  • 在各自平台使用原生最优 I/O 机制(io_uring / IOCP),不降级到 epoll 或 select。
  • 编译期多态(via #ifdef _WIN32 或 traits),避免运行时虚函数开销。

✅ 原则 2:统一 Awaitable 接口

1
2
3
// 用户看到的接口完全一致
auto data = co_await socket.recv(1024);
co_await socket.send(buffer);
  • 底层 recv() 返回一个 Awaitable<T> 对象,在 co_await 时挂起协程,并注册到平台后端。
  • 完成时由后端唤醒协程并返回结果。

✅ 原则 3:协程调度与 I/O 解耦

  • 调度器(Scheduler)管理所有协程生命周期。
  • I/O 后端只负责“通知完成”,不直接操作协程栈。
  • 支持:- 单线程调度(客户端场景)
    • 多线程 work-stealing(服务器场景)

✅ 原则 4:资源安全与 RAII

  • socketbuffertimer 等均支持 RAII。
  • 协程取消时自动清理 pending I/O(io_uring 可 cancel,IOCP 可关闭 socket 触发 ERROR_OPERATION_ABORTED)。

✅ 原则 5:可观察性与调试友好

  • 内置 trace ID、协程上下文日志。
  • 支持 hook 到 Prometheus / OpenTelemetry(可选)。

3. 核心组件设计

组件 说明
coronet::TcpSocket 封装平台 socket,提供 connect, send, recv 等 awaitable 方法
coronet::IoContext I/O 上下文,管理 io_uring ring 或 IOCP completion port
coronet::Scheduler 协程调度器,支持 spawn() 启动新协程
coronet::Timer 高精度定时器(io_uring timeout / Windows waitable timer)
coronet::BufferPool 零拷贝缓冲池,避免频繁内存分配

4. 跨平台实现策略

功能 Linux实现 Windows实现
异步 recv io_uring_prep_recv WSARecv + OVERLAPPED
异步 send io_uring_prep_send WSASend + OVERLAPPED
事件循环 io_uring_wait_cqe GetQueuedCompletionStatusEx
定时器 io_uring_prep_timeout CreateThreadpoolTimerSetWaitableTimer
错误码 errno / -ret WSAGetLastError()

🔧 使用 CMake + feature test 自动启用 io_uring(需 liburing >= 2.0)或 fallback 到 epoll(兼容旧内核)。


三、示例代码(愿景)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <coronet/coronet.hpp>

coronet::Task<void> echo_client(std::string host, uint16_t port) {
coronet::TcpSocket sock;
co_await sock.connect(host, port);

std::string msg = "Hello, CoroNet!";
co_await sock.send(msg);

auto reply = co_await sock.recv(1024);
std::cout << "Reply: " << reply << "\n";
}

int main() {
coronet::IoContext ctx;
ctx.spawn(echo_client("127.0.0.1", 8888));
ctx.run(); // 自动选择 io_uring 或 IOCP
}

四、项目定位与差异化

对比项 Boost.Asio Seastar CoroNet(你的项目)
协程支持 C++20(实验性) 自研 fiber 原生 C++20 协程优先
Linux 后端 epoll aio + dpdk io_uring(最新)
Windows 后端 IOCP ❌ 不支持 IOCP(深度优化)
跨平台 ❌(Linux only)
学习曲线 中高 低(同步风格)

💡 CoroNet 的核心价值
在 Windows 和 Linux 上,都提供接近硬件极限的性能,同时让用户写出最简单的代码。


五、下一步建议

  1. 命名确认:注册 coronet GitHub 仓库(如 github.com/yourname/coronet
  2. MVP 路线图:- 实现 Linux io_uring TCP recv/send
    • 实现 Windows IOCP TCP recv/send
    • 封装统一 Awaitable 接口
    • 添加协程调度器
    • 跨平台 CMake 构建
  3. 参考项目:- folly::AsyncSocket

如果你决定启动这个项目,CoroNet 将填补 C++ 生态中“现代化、跨平台、协程优先、极致性能”网络库的空白。这不仅是技术挑战,更是对 C++ 系统编程未来的一次推动。

CoroNet 协成完整的状态机转换

让我详细展示从创建到销毁的完整生命周期

1
2
3
4
5
6
7
8
9
10
// 示例代码
task<int> make_task() {
co_return 42;
}

task<void> caller() {
auto t = make_task();
int result = co_await t; // ← 这里发生了什么?
}

  1. 阶段 1:Task 创建(未开始)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
make_task() 被调用

创建 task_promise<int>

调用 initial_suspend() → suspend_always

返回 task<int> 对象(包含 coroutine_handle)

此时协程处于:"初始挂起"状态
┌──────────────────────┐
│ task_promise │
│ ├─ state: mono │
│ ├─ value: 未初始化 │
│ └─ parent_coro: │
│ noop_coroutine() │
└──────────────────────┘
  1. 阶段 2:第一次 co_await t
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
执行 co_await t (t 是左值)

调用 t.operator co_await() const &

创建 awaiter 对象
┌──────────────────────┐
│ awaiter │
│ ├─ awaiter_base │
│ │ └─ handle ───────┼──→ task_promise
│ └─ (无额外成员) │
└──────────────────────┘

编译器执行 await_ready()

检查:!handle || handle.done()

返回 false (协程未完成)

【需要挂起 caller 协程】

  1. 阶段 3:await_suspend 建立父子关系
1
2
3
4
5
6
7
8
9
10
11
await_suspend(caller_handle) {
// 1. 设置父协程(谁在等我)
handle.promise().set_parent(caller_handle);

// 内存布局变化:
// task_promise.parent_coro = caller_handle

// 2. 返回子协程句柄(立即执行)
return handle; // ← 切换到 task 协程
}

此时的栈帧关系:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
┌─────────────────┐
│ caller 协程 │ ← 被挂起
│ ├─ state: │
│ │ waiting │
│ └─ resume_point:│
│ after co_await│
└─────────────────┘

│ parent_coro

┌─────────────────┐
│ task 协程 │ ← 正在执行
│ ├─ state: │
│ │ running │
│ └─ promise: │
│ parent_coro = │
│ caller_handle │
└─────────────────┘

  1. 阶段 4:Task 执行完毕
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
task 协程执行:
co_return 42;

调用 promise.return_value(42)

std::construct_at(&value, 42);
state = value_state::value;

┌──────────────────────┐
│ task_promise │
│ ├─ state: value ✅ │
│ ├─ value: 42 │
│ └─ parent_coro ──────┼──→ caller_handle
└──────────────────────┘

调用 final_suspend()

返回 task_final_awaiter

  1. 阶段 5:final_suspend 返回父协程
1
2
3
4
5
6
7
8
template<typename T>
struct task_final_awaiter {
std::coroutine_handle<>
await_suspend(std::coroutine_handle<Promise> current) noexcept {
return current.promise().parent_coro; // ← 返回 caller_handle
}
};

控制权转移:

1
2
3
4
5
6
7
8
9
10
task_final_awaiter.await_suspend()

读取 parent_coro (caller_handle)

返回 caller_handle

调度器恢复到 caller 协程

caller 从 co_await 处恢复执行

  1. 阶段 6:await_resume 获取结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 回到 awaiter::await_resume()
decltype(auto) await_resume() {
assert(this->handle && "broken_promise");
return this->handle.promise().result();
// ↓
// promise.result() 被调用
}

// task_promise::result() &
T &result() & {
if (state == value_state::exception) [[unlikely]] {
std::rethrow_exception(exception_ptr);
}
assert(state == value_state::value); // ✅
return value; // ← 返回 int& (引用到 42)
}

最终结果:

1
2
3
4
int result = co_await t;
// result 绑定到 promise.value 的引用
// result == 42

CoroNet 协成异常机制

  1. 异常产生流程:
1
2
3
4
5
task<int> may_throw() {
throw std::runtime_error("error");
co_return 0; // 不会执行
}

  1. 步骤分解:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
1. 协程执行到 throw

2. 运行时捕获未处理异常

3. 调用 promise.unhandled_exception()

void unhandled_exception() noexcept {
exception_ptr = std::current_exception();
state = value_state::exception;
}

4. 继续执行 final_suspend

5. 返回父协程

6. await_resume() 被调用

7. result() 检查 state

8. std::rethrow_exception(exception_ptr)

9. 异常传播到 caller

io_context 架构图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
graph TD
A[io_context] --> B[worker_meta]
B --> C[io_uring Ring]
B --> D[reap_swap 任务交换区]
B --> E[SPSC Cursor]

F[host_thread] --> A

G[task<void> 协程] --> H[co_spawn]
H --> I[worker_meta::co_spawn_auto]
I --> J{是否跨线程?}
J -->|否 | K[co_spawn_unsafe 本地提交]
J -->|是 | L[msg_ring/eventfd 远程提交]

K --> D
L --> D

M[调度循环] --> N[do_worker_part 执行协程]
M --> O[do_submission_part 提交 IO]
M --> P[do_completion_part 处理完成]

N --> Q[从 reap_swap 取出协程]
Q --> R[resume 协程]
R --> S[协程发起 IO 请求]
S --> T[SQE 提交到 io_uring]

P --> U[CQE 从 io_uring 完成]
U --> V[恢复对应协程]
V --> D

io_context架构图

Buy me a coffee please.