在过去的几天里,我一直在思考如何解决我面临的一个问题,并且我试图研究这个主题,但我真的不知道自己能做些什么。
我在同一结构中有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
}
任何想法或帮助将不胜感激:)
答案 0 :(得分:4)
使用IOCP时,每个异步操作都有两项用户数据。
第一个是完成键,它是“每个连接”数据,并且在通过使用套接字/文件句柄和现有完成端口调用CreateIoCompletionPort()将文件句柄或套接字与完成端口相关联时设置。对于给定连接,每次调用GetQueuedCompletionStatus()时都会返回此值。
第二个是“扩展重叠”结构,即“每个操作”数据。每个并发操作必须为其分配唯一的重叠结构。
在上面的设计中,您应该使用“每个连接”数据来识别您的连接。您有两个链接的连接(套接字),因此我将有两个链接的类,一个用于连接的每一侧。类(或结构,如果你使用的是C而不是C ++)将保存套接字,指向连接另一半的指针以及指示它是哪种连接类型的标志。如果使用C ++,这两个类将派生自一个公共基类,以便您可以调用成员函数来确定完成键表示哪种类型的连接。如果使用C,则使用歧视联盟。
然后,您只需将完成键转换为基础,然后确定您拥有的连接类型并转换为正确的类/结构。您现在知道执行操作的连接。连接类可以存储运行其协议的状态机的所有状态。
正如Criag所提到的,每个重叠的结构都是“每个操作都是唯一的”,在我的IOCP代码中,这往往允许访问操作的数据缓冲区和一个告诉我操作是什么的标志(读/写/接受/连接等)。
一个潜在的复杂性是使每个操作和每个连接数据保持活动状态,直到完成所有使用它的未完成操作。我个人赞成每个连接和每个操作数据的引用计数,但我确信还有其他方法。
我有一些使用这些概念的IOCP示例代码(虽然没有提供“双连接”示例),您可以从这里下载:http://www.serverframework.com/products---the-free-framework.html
答案 1 :(得分:2)
您正在使用的重叠扩展结构非常适合 a 特定连接实例。例如,该结构不仅应包含正在执行操作的套接字,还应包含该操作。例如,可以读取或写入的套接字上的IO完成应该反映IO请求启动时存在的状态。大多数基于IOCP的客户端/服务器代码示例都将证明这种一般意识形态。
在您的情况下,您不应对两个具有两个可能独立操作的不同套接字使用相同的OVERLAPPED结构。如果套接字在某种意义上是“相关的”那么应该在OVERLAPPED结构之外跟踪和维护套接字。每个应该有自己独特的结构,用于自己独特的IO完成。其他任何事都老老实实地要求头疼。
所有这一切,似乎你的用例可能远远没有改变你当前的方案以适应我所描述的。我总是不愿意给出“你不应该这样做”的答案,因为我完全不喜欢自己听到这些答案,但在这种情况下这是不可能的。
一切顺利。