2012-12-21 45 views
4

我正在寫一個小型的3臺服務器和1個客戶端程序。 2臺服務器發送tcp消息,最後一臺服務器使用winsock2發送upd數據報。是winsock2線程安全嗎?

我想知道如果我可以通過使用線程(OpenMP或boost :: threads)來製作simulanious recvfrom(),以便兩個線程同時在同一個端口上偵聽同一個套接字。

我在windows7上使用VC++ 2010。

謝謝你的幫助。

+2

不,插座不是線程安全的,你需要每個線程的插座,然而,使用windows消息循環,您可以通知一個線程從另一個,反之亦然,線程本身可以有消息循環。 – johnathon

+1

「TCP消息」可以被分段; TCP是一個字節流協議。你將如何處理一個線程被另一個線程接收到一半的消息?不可能的事實保護您免受更基本的設計錯誤。在一個線程中接收並重新組裝消息(反正不貴),然後將整個消息分派給其他線程進一步處理。 – MSalters

+0

謝謝你的回覆。我會考慮每個線程使用一個套接字。 – ezzakrem

回答

5

是的,套接字是線程安全的,但是你必須小心。一種常見模式(使用阻塞IO時)是讓一個線程在套接字上接收數據,另一個線程在同一個套接字上發送數據。讓多個線程從套接字接收數據通常對於UDP套接字來說很好,但大多數情況下TCP套接字沒有多大意義。沒有爲WSARecv文檔中警告:

的WSARecv不應 不同的線程同時在同一插座上調用,因爲這可能會導致不可預知的緩衝 秩序。

但是,如果您使用UDP並且協議是無狀態的,那麼通常不會有任何擔憂。

還要注意的是WSAEINPROGRESS錯誤代碼主要適用於1.1的Winsock:

WSAEINPROGRESS:一個阻塞的Windows Sockets 1.1通話過程中,或者服務提供者仍在處理一個回調函數。

WSAEINPROGRESS進一步狀態的描述:

正在進行操作。

阻止操作當前正在執行。 Windows套接字只允許單個阻塞操作 - 每任務或線程 - 處於未完成狀態,並且如果進行任何其他函數調用(無論是否引用該任何其他套接字),該函數將因WSAEINPROGRESS錯誤而失敗。

請注意,這涉及每個任務或線程的單個阻塞操作。

此外,還有針對的WSARecv文檔中的附加警告:

發出任何中斷了同一個線程正在進行阻塞Winsock調用將導致不確定的行爲的APC內的另一個阻塞Winsock調用,並且絕不由Winsock客戶嘗試。

但除了這些警告你應該沒問題。

更新:增加一些外部引用: alt.winsock.programming: Is socket thread-safe?Winsock Programmer’s FAQ: Is Winsock thread-safe?

+0

感謝您提供所有這些明確的信息。所以有可能在兩個線程中的同一個套接字上運行兩個wsarecv。所以我只會在線程中調用兩個阻塞操作而不是整個進程時纔會得到WSAEINPROGRESS錯誤。這是一個好消息,因爲我在每個線程中都有一個recv()。 另一個問題,先生。如果我有兩個UDP源,我可以使用一個線程和一個套接字從這些源接收數據(假設我使用相同的端口)? – ezzakrem

+0

對於UDP,您通常會使用recvfrom來獲取數據以及對等方的地址和端口號,以便您可以將答覆發回到請求來自的地方。由於無論如何都沒有連接,每個數據包是來自同一個發送者還是來自不同的發送者並不重要。 – cmeerw

1

Winsock在套接字上只允許一個阻塞IO調用。來自不同線程的多個阻塞調用將以「WSAEINPROGRESS」錯誤結束。 http://msdn.microsoft.com/en-us/library/windows/desktop/ms740668%28v=vs.85%29.aspx#WSAEINPROGRESS

如果你想做併發IO請求,你可以嘗試使用異步IO或者重疊IO(用windows的說法)。但我想你會想要併發處理數據而不是併發讀取數據。在這種情況下,您可以讓一個線程發出IO請求,並處理其他線程。

+0

我非常懷疑 - 文檔指出「單個任務或線程阻塞操作」。對WSARecv的描述進一步說明:「在APC內部發出另一個阻塞的Winsock調用,這會中斷正在進行的同一線程上的阻塞Winsock調用,將導致未定義的行爲,並且決不能由Winsock客戶端嘗試。 – cmeerw

+0

該文檔談論APC「異步過程調用」將在發出阻塞調用的同一線程上運行的情況。由於APC會在線程恢復之前得到執行 - 用戶模式APC確實有機會運行 - 並且如果它發出另一個阻塞套接字調用,則行爲未定義。爲了給出代碼透視圖,文檔正在討論在recv或WSARecv仍在執行的同一個線程上運行的一些代碼,這隻有在未完成的APC排隊等待線程時纔有可能。 – nanda

+0

是的,重點在於多個阻塞呼叫只是同一個線程上的一個問題。但在使用多線程時不會(每個線程阻塞一次就可以)。 – cmeerw