密集数据发送中断 IOCP 事件

intensive data sending breaks IOCP events

我在我的应用程序中使用 Windows IOCP 几年没有任何问题(与小消息的永久 TCP 通信),但最近我不得不发送非常大的应用程序状态(25k 条消息,大约总共 12Mb)。

我使用 0x2000 字节的缓冲区,结合 IOCP 事件:第一个 write 触发器 WSASend,所有其他的只是填充缓冲区。当 GetQueuedCompletionStatus 收到事件时,写入完成,下一个缓冲区通过 WSASend 发送,依此类推。

这是我第一次使用这样的用例一次发送这么大的数据。我注意到,一段时间后 GetQueuedCompletionStatus 停止接收事件。

这是可视化的,缓冲区中的数据是如何从 IOCP 回调发送的:

14:16:19.894, WSASend scheduled buffer size (3005) , pendingWrite bytes 3005
14:16:20.021, WSASend scheduled buffer size (1175) , pendingWrite bytes 1175
14:16:20.276, WSASend scheduled buffer size (4652) , pendingWrite bytes 4652
14:16:20.411, WSASend scheduled buffer size (2135) , pendingWrite bytes 2135
14:16:20.604, WSASend scheduled buffer size (3366) , pendingWrite bytes 3366
14:16:20.835, WSASend scheduled buffer size (3718) , pendingWrite bytes 3718
14:16:20.943, WSASend scheduled buffer size (665)  , pendingWrite bytes 665
14:16:21.087, WSASend scheduled buffer size (2931) , pendingWrite bytes 2931
14:16:21.109, WSASend scheduled buffer size (296)  , pendingWrite bytes 296
14:16:21.109, WSASend scheduled buffer size (21)   , pendingWrite bytes 21
14:16:21.182, WSASend scheduled buffer size (380)  , pendingWrite bytes 380
14:16:21.184, WSASend scheduled buffer size (160)  , pendingWrite bytes 160
14:16:21.355, WSASend scheduled buffer size (5885) , pendingWrite bytes 5885
14:16:21.531, WSASend scheduled buffer size (8169) , pendingWrite bytes 16135 <-- here buffers start growing
14:16:21.691, WSASend scheduled buffer size (8173) , pendingWrite bytes 19727
14:16:21.692, WSASend scheduled buffer size (8176) , pendingWrite bytes 11554

如您所见,过了一会儿,pendingWrite 开始增长,但没关系,我有很多内存来缓冲它。但是在最后一次发送之后(在 14:16:21.692GetQueuedCompletionStatus 根本不会触发。

我尝试将 send/receive 套接字缓冲区 (SO_RCVBUF/SO_SNDBUF) 增加到 80Kb,但看起来没有任何效果。

我不知道,接下来我应该检查什么,WSASend 没有 return 任何错误(只有 ERROR_IO_PENDING 是预期的)。

PS:通信在同一台PC上,Windows 7 x64。

简而言之:我的假设是,代码运行良好l,所以我猜想,IOCP(或套接字)设置不适合这样的吞吐量,或者也许套接字缓冲区有一些限制。

回答:代码有竞争条件,所以有时 receiver 停止从套接字中消耗数据,这就是为什么 sending 套接字的缓冲区最终达到了它的限制,并且GetQueuedCompletionStatus 套接字的写回调没有触发新事件。

总结:IOCP 按预期工作,不需要额外的配置。

当 race 固定后,我可以在瞬间发送超过 150k 的小数据包(20-200 字节)。