2012-06-06 40 views
1

我正在实现一个客户机/服务器对,通过TCP/IP套接字进行通信,在Windows中使用带有完成例程的重叠IO进行通信。调试通过两个VirtualBox虚拟机完成(客户端在一个,服务器在另一个)。 CPU是一个四核。WSASend,WSARecv完成例程安排问题

在客户端上的操作顺序基本是:

  • 问题一个电话的WSARecv(不会完全作为尚未)。
  • 使用数据包发出WSASend调用。服务器将通过相同的套接字发送回复。
  • 一旦WSASend调用的完成例程被执行,数据包被放置在等待应答队列中。
  • 一旦WSARecv调用的完成例程执行(从收到的服务器回复),代码将尝试在队列中查找与此回复相关的数据包。
  • 发出WSARecv调用(至今尚未完成)。
  • 从第二步开始重复。

在服务器上的操作顺序基本是:

  • 问题一个电话的WSARecv(不会完全作为尚未)。
  • 执行WSARecv调用的完成例程(来自接收到的客户端的数据包)后,该数据包将在辅助线程中处理。
  • 发出WSARecv调用(至今尚未完成)。
  • 一旦辅助线程完成,回复被发送到客户端,在主线程上发出WSASend调用。
  • 从第二步开始重复。

我遇到的问题是,有时会在客户端收到回复,而在等待回复队列中没有相应的数据包。作为调试工作的一部分,我有两个问题:

1)可以想象,有一个未决的WSARecv调用,WSARecv的完成例程被安排在对应的WSASend的完成例程之前执行(一个发送服务器回复的数据包)?

2)如果WSASend调用立即完成,那么完成例程仍然计划执行?

我正在使用WSAWaitForMultipleEvents调用作为可警告的等待函数。

回答

1

您的代码已损坏。即使操作保证按特定顺序完成,也不能确保以任何特定顺序收到完成指示,或者处理这些完成的代码将按任何特定顺序运行。

对第二个问题的回答是。通常,您可以将即时完成视为挂起,因为完成例程将在两种情况下运行。

对于您的问题的理想解决方案是在您决定发送它时立即考虑数据包等待回复。

如果由于某些原因需要进行太多的代码更改,您还有其他选择。如果您收到WSARecv完成并且WSASend完成尚未发生,则只需推迟处理WSARecv完成。你可以这样做两种方式:

  1. 产生一个线程等待几分之一秒,然后重新发布该完成通知(通过调用PostQueuedCompletionStatus)从该线程。据推测,WSASend届时将完成。

  2. 标记WSARecv已完成的标志并保存完成信息。当WSASend完成时,请注意该标志并处理WSARecv。 (可能通过直接呼叫完成处理程序。)