1

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

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

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

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

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

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

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

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

我正在使用 WSAWaitForMultipleEvents 调用作为警报等待函数。

4

1 回答 1

1

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

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

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

如果由于某种原因需要进行太多代码更改,您还有另一种选择。如果您收到 WSARecv 完成并且 WSASend 完成尚未发生,只需推迟处理 WSARecv 完成。您可以通过以下两种方式执行此操作:

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

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

于 2012-06-06T09:21:52.440 回答