【问题标题】:SetFileCompletionNotificationModes seems to not work properlySetFileCompletionNotificationModes 似乎无法正常工作
【发布时间】:2014-05-02 06:57:37
【问题描述】:

我正在使用SetFileCompletionNotificationModes() API 来优化我的 I/O 完成端口循环,但它似乎无法正常工作。 即使我为套接字和 HANDLE 设置了 FILE_SKIP_COMPLETION_PORT_ON_SUCCESS,如果 ReadFile() WriteFile() WSARecv() WSASend() 确实返回 synchronosly,仍然会调用 I/O 端口的完成回调。

我确定 MSDN 所说的 3 个条件必须为真(完成端口与文件句柄相关联,文件已为异步 I/O 打开文件,请求立即返回成功而不返回 ERROR_PENDING),并且都是真的,那为什么我仍然会收到 I/O 完成调用?

当我调用SetFileCompletionNotificationModes() 时,它返回成功,所以没有错误或任何错误,系统是 Windows 7。

当我在我的套接字/HANDLE 上激活SetFileCompletionNotificationModes() 后,我可以清楚地看到 I/O 完成回调不会被调用时,如何复制一个场景?

我猜是当我在套接字上写入几个字节时会发生这种情况,因为套接字的缓冲区很大,我没有把它填满,所以另外几个字节的另一个写入不应该阻塞,因为还有很多缓冲区中的空间,所以它应该立即返回,但不是 ERROR_IO_PENDING,只是以同步方式,对吧? (或多或少,以类似于 unix EWOULDBLOCK/EAGAIN 的方式:当我为几个字节调用 write() 时,它会立即返回,并且不会返回 EAGAIN,因为写入缓冲区中仍有空间)。

好吧,它不会那样做。即使在一个套接字上多次写入几个字节,它仍然调用 I/O 完成回调,避免设置 FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 的好处

我错过了什么重要的东西吗?有什么线索吗?

注意:我知道如果套接字仅与返回可安装文件系统 (IFS) 句柄的分层服务提供程序 (LSP) 兼容,这将不起作用,但这不是我的情况,它应该起作用。 顺便说一句,我也在尝试使用管道和文件。

文件不应该永远不会调用 I/O 完成回调,因为它们永远不会阻塞,就像 unix 中的 read()write() 调用本地文件永远不会返回 EWOULDBLOCK/EAGAIN,所以 ReadFile()WriteFile() 带有用 FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 设置的句柄应该立即返回吗?

【问题讨论】:

  • 显示关联完成端口并调用 SetFileCompletionNotificationModes() 的代码。我预计您的代码中存在错误...
  • 好吧,为了确定这不是一个错误,我将再次检查代码并进行更多测试。现在它适用于命名管道,但不适用于 tcp/udp 套接字。顺便说一句,基本上代码是if (pSetFileCompletionNotificationModes != 0) pSetFileCompletionNotificationModes(handle, flags);

标签: c++ sockets winapi io iocp


【解决方案1】:

仅当网络堆栈不再需要您提供的数据缓冲区时,才会生成网络写入完成。很难推断何时会发生这种情况,而且这也有些无关紧要,无需担心。当您发出带有 FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 设置的重叠写入时,当且仅当同步完成时,您的写入操作才会返回 0。编写代码来正确处理这种情况(它与 recv 端所需的代码相同)并忘记它。在可能的情况下,您将获得性能和上下文切换的优势,而您的代码在不可能的情况下也能正常工作。

至于文件系统访问,这取决于文件系统驱动程序,并且可能取决于实际硬件。请参阅here,了解有关让某些硬件完全执行异步文件写入有多难的信息。然后请注意,当我将我所说的测试从具有“普通”SATA 磁盘的工作站切换到具有硬件 RAID 的服务器时,一切都不同了,所有的写入总是完全异步的......

【讨论】:

    【解决方案2】:

    确保验证documentation 中提到的第4 个条件:

    当FileHandle参数为socket时,该模式只兼容返回可安装文件系统(IFS)句柄的Layered Service Providers(LSP)。检测是否安装了非IFS LSP ,使用 WSAEnumProtocols 函数并检查每个返回的 WSAPROTOCOL_INFO 结构中的 dwServiceFlag1 成员。如果 XP1_IFS_HANDLES (0x20000) 位被清除,则指定的 LSP 不是 IFS LSP。鼓励拥有非 IFS LSP 的供应商迁移到 Windows 过滤平台 (WFP)。

    另请阅读此 MSDN 支持票:

    SetFileCompletionNotificationModes API causes an I/O completion port not to work correctly if a non-IFS LSP is installed

    【讨论】:

    • 正如我之前发布的,套接字有一个 IFS LSP,它直接与 AFD 驱动程序对话(例如,它的 WSAPROTOCOL_INFOW.ProtocolChain.ChainLen 为 1)所以这不是 FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 不应该工作的情况带插座。奇怪的是,我也在尝试使用管道或文件,但它似乎也不在那里工作......
    猜你喜欢
    • 2017-09-04
    • 2012-05-06
    • 2013-02-17
    • 2017-10-09
    • 2017-08-03
    • 2011-09-11
    • 2016-02-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多