IOCP与epoll不可直接比吞吐量,因二者分属Proactor与Reactor不同抽象层级:epoll仅通知就绪需用户调recv搬数据,IOCP则由内核完成数据搬运后才通知。

没有“极限制吞吐量”可比——IOCP 和 epoll 不在同一个抽象层级上,硬比数字只会误导决策。
epoll_wait 返回后必须立刻调用 recv() 或 read()
这是 Reactor 模式的核心约束:epoll 只通知“可读”,不搬运数据。你写的代码必须承担内存拷贝和系统调用开销。
- 用水平触发(LT)但没清空缓冲区?
epoll_wait()下次还会返回该 fd,而你的线程可能卡在前一次recv()的阻塞拷贝里 - 用边缘触发(ET)但只调一次
recv()?只要内核缓冲区还有数据,就再也收不到通知,直接丢包 - 单线程高吞吐场景下,
recvmmsg()批量接收、SO_RCVLOWAT控制唤醒阈值、零拷贝AF_XDP等才是提效关键,不是 epoll 本身能提供的
IOCP 的 WSARecv() 提交即返回,搬运由内核完成
这是 Proactor 模式的实质:你提交一个带 OVERLAPPED 的请求,函数立刻返回;内核在后台把网卡数据填进你传入的缓冲区,完成后才投递完成包。
通过 SSH 隧道从 Android 设备在互联网上对 Windows PC 实现完整远程控制的设置与使用指南,适用于远程桌面访问、安全 RDP 等。
- 应用线程完全不参与数据搬运,可以持续投递新请求(比如一边等上次 recv 完成,一边再发一次 recv)
- 多个线程安全共用一个 IOCP 句柄,
GetQueuedCompletionStatus()是无锁取包,调度由内核闭环完成 - 错误(如连接断开、缓冲区满)是在完成阶段才暴露,调试时容易滞后,日志里看到的失败往往不是出问题的那个调用点
所谓“epoll 吞吐更高”的测试,基本都混了三类干扰
公开对比中常见的 1000MB/s vs 400MB/s 结论,几乎都踩了这些坑:
- 物理层就不一致:
ifconfig显示虚拟机网卡是 1000M,XP 主机是 100M,底噪差 10 倍 - 线程模型不对等:epoll 测的是单线程,IOCP 测的是多线程但没启用线程池模式,根本没发挥完成端口的负载均衡能力
- 数据包大小敏感:IOCP 在 20KB 包下 CPU 占用仅 1%,800KB 包下飙升到 80%——说明其吞吐严重依赖缓冲区管理策略;epoll 对包长更钝感,但代价是每次
recv()都有固定上下文切换成本
真正要选型,得先问清楚:你愿不愿意把数据搬运这件事交给内核?如果需要细粒度控制读写时机、协议解析节奏、错误注入点,epoll 更透明;如果追求极致吞吐下延迟稳定、线程数与连接数解耦、零拷贝发送(TransmitFile),IOCP 是更封闭但也更省心的选择。跨平台项目现在更常绕过二者,直接切到 io_uring——它才是真正接近 IOCP 能力的 Linux 原生异步接口。

















