应用层网络编程范式
前言
在不考虑内核层的情况下,选用Linux底层支持的posix API和网络协议栈。对于应用层网络编程方案总结如下。其中主要针对两个角度:IO模型、编程模型。其中IO模型可参考Linux下IO模型,一般分为五种:阻塞IO、非阻塞IO、信号驱动IO、IO多路复用、异步IO。编程模型分为两种:同步编程、异步编程。其中对于IO模型不再赘述,对于编程模型而言,同步编程更好理解,开发效率更高。异步编程实现方式一般两种:线程池、回调函数。优点是为了提高效率,缺点也很明显开发时如果选用线程池则会带来开销,而回调函数在开发时难理解,且开发难度大,容易陷入“回调地狱”。针对上述两个角度介绍以下内容:
一、常用范式
-
线程池 + 阻塞 I/O(BIO)
-
Reactor + epoll(同步非阻塞IO + 回调)
-
原生io_uring + 回调
-
协程(封装底层同步非阻塞I/O或异步I/O)
二、介绍
1. 线程池 + 阻塞 I/O (BIO)
-
I/O 模型:同步阻塞 I/O
-
编程模型:同步(每个线程顺序执行阻塞操作)
-
工作机制:
-
主线程
accept
连接,分发给 Worker 线程池。 -
每个 Worker 线程阻塞在
read
/write
上,处理单一连接。
-
-
适用场景:低并发、CPU 密集型任务,或兼容性要求高的简单服务。
-
性能瓶颈:线程数 ≈ 并发连接数,上下文切换开销大,无法应对高并发。
2. Reactor + epoll(同步非阻塞 I/O + 回调)
-
I/O 模型:同步非阻塞 I/O
-
编程模型:异步(事件驱动 + 回调函数或状态机)
-
工作机制:
-
单线程(或少量线程)运行事件循环,调用
epoll_wait
监听 I/O 就绪事件。 -
事件就绪后,触发注册的回调函数处理数据(需主动调用非阻塞的
read
/write
)。
-
-
优势:高并发支持(单线程处理万级连接)。
-
缺点:回调地狱(Callback Hell),逻辑碎片化。
-
代表:Netty (Java)、libevent (C)、Tornado (Python)
3. 原生 io_uring 的异步 I/O
-
I/O 模型:异步 I/O (AIO)
-
编程模型:异步(回调或 Future/Promise)
-
工作机制:
-
提交 I/O 请求(如
read
/write
)到内核队列(SQ),立即返回。 -
内核完成操作后,将结果放入完成队列(CQ),应用异步收割结果。
-
无需应用再次发起数据拷贝调用(区别于
epoll
)。
-
-
优势:零拷贝、批处理、更低延迟(避免二次系统调用)。
-
代表:Tokio(Rust, 可选后端)、liburing (C)
4. 协程(封装底层同步非阻塞I/O或异步I/O)
-
I/O 模型:
-
底层为
epoll
→ 同步非阻塞 I/O -
底层为
io_uring
→ 异步 I/O
-
-
编程模型:同步风格写异步代码
-
工作机制:
-
协程在 I/O 等待时挂起(Yield),由调度器切换到其他就绪协程。
-
底层仍依赖事件循环(
epoll
或io_uring
)。
-
-
优势:开发体验极佳(无回调地狱)、天然支持多核调度。
-
代表:
-
epoll
后端:Goroutine (Go)、asyncio (Python) -
io_uring
后端:Tokio (Rust)、Glommio (Rust)
-
更多资料:0voice · GitHub