从I/O完成端口删除句柄以及有关IOCP的其他问题

Eta*_*tan 7 c sockets windows file iocp

CreateIoCompletionPort功能允许创建新的I/O完成端口以及将文件句柄注册到现有I/O完成端口.

然后,我可以使用任何函数,如recv在套接字上或ReadFile在具有OVERLAPPED结构的文件上启动异步操作.

我必须检查函数调用是否同步返回,尽管它是用OVERLAPPED结构调用的,在这种情况下直接处理它.在另一种情况下,当ERROR_IO_PENDING返回时,我可以使用GetQueuedCompletionStatus在操作完成时通知的功能.

出现的问题是:

  • 如何从I/O完成端口删除句柄?例如,当我向IOCP添加套接字时,如何删除已关闭的套接字?我应该用相同的完成键重新注册另一个套接字吗?

  • 另外,有没有办法使调用始终通过I/O完成端口并且不同步返回?

  • 最后,例如可以recv异步但send同步吗?例如,当实现一个简单的echo服务时:我可以等待recv新数据的异步但是send以同步方式响应,以便降低代码复杂性吗?在我的情况下,recv在处理第一个请求之前,我不会第二次.

  • 如果ReadFile已经请求了异步,但在完成之前,WriteFile应该处理相同的文件.是否会ReadFile被错误消息取消,我必须在写入完成后立即重新启动读取过程?或者我必须ReadFile在写作之前手动取消?这个问题与通信设备结合产生; 因此,如果同时发生,写入和读取不应该出现问题.

Aar*_*otz 11

如何从I/O完成端口删除句柄?

根据我的经验,您无法将句柄与完成端口取消关联.但是,您可以通过设置OVERLAPPED结构hEvent字段的低位来禁用完成端口通知:请参阅GetQueuedCompletionStatus的文档.

例如,当我向IOCP添加套接字时,如何删除已关闭的套接字?我应该用相同的完成键重新注册另一个套接字吗?

没有必要明确地将句柄与I/O完成端口解除关联; 关闭手柄就足够了.您可以将多个句柄与相同的完成键相关联; 确定哪个请求与I/O完成相关联的最佳方法是使用该OVERLAPPED结构.实际上,您甚至可以扩展OVERLAPPED以存储其他数据.

另外,有没有办法使调用始终通过I/O完成端口并且不同步返回?

这是默认行为,即使ReadFile/ WriteFile返回TRUE.你必须显式调用SetFileCompletionNotificationModes通知Windows时不排队完成包TRUEERROR_SUCCESS返回.

有可能例如recv异步但send同步吗?

不是通过使用recvsend; 你需要使用接受功能OVERLAPPED结构,如WSARecv,WSASend,或者ReadFileWriteFile.如果您的代码用于处理多种类型的I/O句柄(例如套接字和命名管道),则使用后者可能会更方便.这些函数提供同步模式,因此如果您使用它们,您可以混合异步和同步调用.

如果已经请求了异步ReadFile会发生什么,但在它完成之前,应该处理同一文件的WriteFile?

没有隐含的取消.只要您OVERLAPPED对每个全双工设备的读/写使用单独的结构,我就没有理由不能进行并发I/O操作.


Ken*_*eno 6

正如我已经在那里指出的那样,人们普遍认为不可能从完成端口删除句柄是错误的,这可能是由于几乎所有我能找到的文档都有关于如何做到这一点的任何提示的荒谬.实际上,它很简单:

NtSetInformationFile使用FileReplaceCompletionInformation枚举器值调用FileInformationClass和指向参数FILE_COMPLETION_INFORMATION结构的指针FileInformation.在此结构中,将Port成员设置为NULL(或nullptr在C++中)以将文件与其当前连接的端口解除关联(我猜如果它没有连接到任何端口,则不会发生任何事情),或者将其设置PortHANDLE对另一个端口有效将文件与该文件相关联的完成端口.