0

在过去的几天里,我一直在思考如何解决我面临的一个问题,我试图研究这个话题,但我真的不知道我能做什么。

我在同一个结构中有 2 个套接字,它们都具有相同的完成端口。问题是,它们都使用不同的协议。有没有办法可以找出触发了哪个套接字?他们叫game_socket,和client_socket

示例代码将类似于...

while (true) {
error = GetQueuedCompletionStatus(CompletionPort, &BytesTransfered, (PULONG_PTR)&Key, &lpOverlapped, 0);
srvc = CONTAINING_RECORD ( lpOverlapped, client , ol );
if ( error == TRUE ) {
cout << endl << "SOCKET: [" << srvc->client_socket << "] TRIGGERED - WORKER THREAD" << endl;
cout << endl << "BytesTransfered: [" << BytesTransfered << "]" << endl;

if ( srvc->game_client triggered ) {
// .. this code
} else {

// .. this code
}

任何想法或帮助将不胜感激:)

4

2 回答 2

4

使用 IOCP 时,每个异步操作都可以使用两项用户数据。

第一个是完成键,它是“每个连接”数据,当您通过调用 CreateIoCompletionPort() 与套接字/文件句柄和现有完成端口将文件句柄或套接字与完成端口相关联时设置。对于给定连接,每次调用 GetQueuedCompletionStatus() 时都会返回此值。

第二个是“扩展重叠”结构,即“按操作”数据。每个并发操作必须具有为其分配的唯一重叠结构。

在您上面的设计中,您应该使用“每个连接”数据来识别您的连接。您有两个链接的连接(套接字),所以我将有两个链接的类,一个用于连接的每一侧。该类(或结构,如果您使用的是 C 而不是 C++)将保存套接字、指向另一半连接的指针和一个指示它是哪种类型的连接的标志。如果使用 C++,这两个类将派生自一个公共基类,以便您可以调用成员函数来确定完成键代表的连接类型。如果使用 C,请使用有区别的联合。

然后,您只需将完成键转换为基础,然后确定您拥有的连接类型并转换为正确的类/结构。您现在知道在哪个连接上执行了操作。连接类可以存储运行其协议的状态机的所有状态。

正如 Criag 所提到的,每个重叠的结构都是“每个操作唯一的”,在我的 IOCP 代码中,这往往允许访问操作的数据缓冲区和一个告诉我操作是什么的标志(读/写/接受/连接等) )。

一个潜在的复杂性是让每个操作和每个连接数据保持活动状态,直到使用它的所有未完成的操作完成。我个人喜欢对每个连接和每个操作数据进行引用计数,但我相信还有其他方法。

我有一些使用这些概念的 IOCP 示例代码(虽然不提供“双连接”示例),您可以从这里下载:http ://www.serverframework.com/products---the-free-框架.html

于 2012-09-05T08:21:35.650 回答
2

您使用的重叠扩展结构非常适合特定的连接实例。例如,该结构不仅应包含正在执行操作的套接字,还应包含操作。例如,可能正在读取或写入的套接字上的 IO 完成应反映启动 IO 请求时存在的状态。大多数基于 IOCP 的客户端/服务器代码示例将证明这种普遍的意识形态。

在您的情况下,您不应该对具有两个可能独立操作的两个不同套接字使用相同的 OVERLAPPED 结构。如果套接字在某种意义上是“相关的”,那么应该在您的 OVERLAPPED 结构之外进行跟踪和维护。每个都应该有自己独特的结构来完成自己独特的 IO 完成。老实说,其他任何事情都让人头疼。

话虽如此,您的用例似乎距离改变您当前的方案以适应我所描述的内容并不遥远。我总是不愿意给出“你不应该那样做”的答案,因为我自己完全讨厌听到这些答案,但在这种情况下,这仍然是有必要的。

祝一切顺利。

于 2012-09-03T03:54:53.770 回答