2012-06-06 37 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。 (可能通過直接呼叫完成處理程序。)