如何使用带有套接字的重叠 I/O?

Posted

技术标签:

【中文标题】如何使用带有套接字的重叠 I/O?【英文标题】:How to use Overlapped I/O with sockets? 【发布时间】:2015-04-23 23:24:08 【问题描述】:

我想在我的服务器中使用 Overlapped I/O,但是我找不到很多关于这个主题的教程(大部分教程都是关于 Overlapped I/O with Completion Ports,我想使用回调函数) .

我的服务器一次最多可以连接 400 个客户端,并且它只会长时间发送和接收数据(每 30 秒,服务器和客户端之间会交换几千字节的数据)。

我想使用 Overlapped I/O 的主要原因是因为select() 最多只能处理 64 个套接字(而我有 400 个!)。

所以我会告诉你我是如何理解重叠 I/O 的,如果我错了,请纠正我:

如果我想从其中一个客户端接收数据,我使用WSARecv() 并提供套接字句柄和一个要填充接收数据的缓冲区,我还提供一个回调函数。当接收到数据并填充到缓冲区时,会调用回调函数,我可以对数据进行处理。 当我要发送数据时我使用WSASend(),我还提供了套接字句柄和回调函数,以及当数据发送时(不确定是何时放置在底层发送缓冲区或实际放置在线路上) ,也会调用回调告诉我数据已发送,我可以发送下一条数据。

【问题讨论】:

我建议使用像 boost::asio 这样的库。 【参考方案1】:

您似乎有一个误解是 OVERLAPPED 回调实际上是同步的。

你说:

当接收到数据并填充到缓冲区时,会调用回调函数

现实:

当调用一个可报警的等待函数(例如SleepExMsgWaitForMultipleObjectsEx)时,如果已经接收到数据并填充到缓冲区中,将调用回调函数

只要您意识到这一点,您就应该保持良好状态。我同意你的观点,在你的场景中,使用回调重叠 I/O 是一种很好的方法。因为回调发生在执行 I/O 的线程上,所以您不必担心同步来自多个线程的访问,这与线程池上的完成端口和工作项需要的方式相同。

哦,还要确保检查WSA_IO_PENDING,因为如果已经缓冲了足够的数据(用于接收)或缓冲区中有足够的空间(用于发送),则操作可以同步完成。在这种情况下,回调将发生,但它会排队等待下一个警报等待,它永远不会立即运行。某些错误也会同步报告。其他人会来你的回电。

此外,对于返回 0WSA_IO_PENDING 的每个操作,无论该操作成功完成、被取消还是出现其他错误,都保证您的回调恰好排队一次。在回调发生之前,您不能重用缓冲区。

【讨论】:

@HarryJohnston:无论有多少套接字,从网络读取数据都不会使单个内核饱和。您可能有相关的计算可以,但您可以将其分配给工作线程。不需要 I/O 层为您做这件事。绝对不需要 I/O 层强迫您使用工作线程并在计算量不合理时为同步付费(瞪眼 .NET 基类库)。 @HarryJohnston:我敢肯定你喜欢的 10Gbs 网卡(及其驱动程序)支持 DMA,它不会加载你的 CPU。虽然将工作交给工作线程可能涉及上下文切换,但您不认为 I/O 完成端口也必须这样做吗?这只是它是否在您的控制或 I/O 层之下的问题。 DMA 是一个红鲱鱼 IMO,因为它只会影响您无法控制的 I/O 部分,我希望将 IOCP 数据包发送到最佳可用线程在内核中处理.但是再想一想,我认为你是对的;如果您使用无锁队列将作业移交给工作线程,它们可以完全倾斜,甚至可以避免检索下一个 IOCP 数据包所涉及的内核模式转换 - 所以如果有任何事情它应该执行 更好.【参考方案2】:

IO完成回调机制很好用,我用过几次,没问题。在 32 位系统中,您可以将套接字上下文实例的“this”放入 OVERLAPPED 结构的 hEvent 字段并在回调中检索它。不知道如何在 64 位系统中做到这一点:(

【讨论】:

通过在 OVERLAPPED 结构之后添加额外数据...Raymond Chen describes it here 和更多here 所以不要滥用 hEvent。 @BenVoigt 对齐问题:( 没有问题。您正确对齐分配更大的结构,并且它的对齐至少与成员 OVERLAPPED 结构一样好。而且 Win32 并不关心你是否传递给它一个恰好过度对齐的指针。

以上是关于如何使用带有套接字的重叠 I/O?的主要内容,如果未能解决你的问题,请参考以下文章

四.Windows I/O模型之重叠IO(overlapped)模型

如何使用重叠 I/O 检测到命名管道服务器的客户端连接?

重叠 I/O:如何在完成端口事件或正常事件上唤醒线程?

I/O 完成端口,如何释放每个套接字上下文和每个 I/O 上下文?

Linux 和 I/O 完成端口?

Libevent 和文件 I/O