IO完成端口密钥混淆

2024-05-19 17:03:58 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在编写一个基于IO完成端口的服务器(source code here),使用Python中的windowsdllapi使用ctypes模块。但这是API的一个非常直接的用法,这个问题是针对那些了解IOCP而不是Python的人。在

根据我对CreateIoCompletionPort的文档的了解,当您使用与创建的IOCP关联的文件句柄(在我的例子中是套接字)调用此函数时,可以指定“用户定义的”完成键。当您开始调用GetQueuedCompletionStatus时,您将获得一个完成键值以及一个指向重叠对象的指针。完成键应该标识哪些重叠的对象和请求已经完成。在

但是,假设我在CreateIoCompletionPort调用中传入100作为一个重叠对象的完成键。当同一个重叠对象的IO已完成并通过GetQueuedCompletionStatus返回时,伴随它的完成键要大得多,与原始值100没有任何相似之处。在

我是不是误解了完成键的工作原理,还是我在上面链接的源代码中做得不对?在


Tags: 模块对象端口io服务器apisource用法
3条回答

GetQueuedCompletionStatus返回两个东西,OVERLAPPED结构和一个完成键。完成键表示每个设备的信息,OVERLAPPED结构表示每次调用的信息。完成键应该与调用CreateIoCompletionPort中给出的匹配。通常,您将使用指向包含有关连接信息的结构的指针作为完成键。在

看起来您没有使用completionKey执行由GetQueuedCompletionStatus返回的任何操作。在

我猜你想:

if completionKey != acceptKey:
    Cleanup()
    ...

编辑:

Python是否知道在CreateAcceptSocket中创建的OVERLAPPED结构正被win32api异步使用并阻止它被GC'd?在

我在日常实践中发现,最好只关注OVERLAPPED的结果,因为这不会改变。有效使用它的一种方法是使用如下内容:

struct CompletionHandler
{
    OVERLAPPED dummy_ovl;
    /* Stuff that actually means something to you here */
};

当您向IOCP发布内容时(无论是通过I/O调用还是仅仅通过win32api发布),首先创建一个用于跟踪调用的CompletionHandler对象,并将该对象的地址强制转换为OVERLAPPED*。在

^{2}$

这样,当您得到OVERLAPPED结果时,您所要做的就是将它转换回CompletionHandler然后瞧!你有你电话的原始背景。在

OVERLAPPED* from_queued_completion_status;
// Actually get a value into from_queued_completion_status

CompletionHandler* handler_for_this_completion = (CompletionHandler*)from_queued_completion_status;
// Have fun!

有关实际设置的更多详细信息,请查看Boost的ASIO For Windows实现(ver 1.42 header here)。有一些细节,比如验证从GetQueuedCompletionStatus获得的OVERLAPPED指针,但是同样,请参阅链接以获得实现的好方法。在

您应该将完成键视为“按连接”数据,将(扩展)重叠结构视为“按i/o”操作。在

有些人将扩展重叠结构用于两者,并将所需的所有信息存储在扩展重叠结构中。我总是存储一个引用计数的对象,它将套接字包装在完成键中,并将引用计数的数据缓冲区作为扩展的重叠结构。如果你感兴趣,你可以看看some example IOCP code in C++ here。在

实际上,完成键只是一个不透明的数据句柄,当套接字完成时,I/O完成系统将返回给您。在

相关问题 更多 >