WSASend,WSARecv完成例程调度问题

时间:2012-06-06 05:06:32

标签: sockets io

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

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

  • 发出WSARecv调用(目前尚未完成)。
  • 使用数据包发出WSASend调用。服务器将通过同一个套接字发送回复。
  • 执行WSASend调用的完成例程后,数据包将被置于等待回复队列中。
  • 执行WSARecv调用的完成例程(收到服务器的回复)后,代码会尝试在队列中找到与此回复相关的数据包。
  • 发出WSARecv调用(目前尚未完成)。
  • 从第二步开始重复。

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

  • 发出WSARecv调用(目前尚未完成)。
  • 执行WSARecv调用的完成例程(收到客户端的数据包)后,将在辅助线程中处理该数据包。
  • 发出WSARecv调用(目前尚未完成)。
  • 一旦辅助线程完成,回复将发送到客户端,在主线程上发出WSASend调用。
  • 从第二步开始重复。

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

1)可以想象,在挂起WSARecv调用的情况下,WSARecv的完成例程被安排在相应WSASend(发送服务器回复的数据包的那个)的完成例程之前执行吗? / p>

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

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

1 个答案:

答案 0 :(得分:1)

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

第二个问题的答案是。通常,您可以将立即完成视为待处理,因为完成例程将在任何一种情况下运行。

解决问题的理想方法是在您决定发送数据包后立即考虑等待回复。

如果由于某种原因需要更改代码,您还有另一种选择。如果您收到WSARecv完成并且尚未完成WSASend完成,则只需延迟处理WSARecv完成。你可以这两种方式:

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

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