在同一個套接字上可以進行多少個非同步套接字請求?
當我在套接字上呼叫 BeginSend 時,我傳遞了一個委託,該委託將在發送數據時(由不同的執行緒)呼叫。
如果我在第一次尚未“回調”時再次呼叫 BeginSend 會發生什麼?
發送數據的正確行為是什麼?做 BeginSend,然後在回調上做 EndSend 並開始另一個發送?或者讓多個 BeginSends 同時工作是否明智?
這是 MSDN 上的 BeginSend 頁面,它沒有回答這個問題:BeginSend msdn
正如 OKW 所說,多個掛起的
BeginSend呼叫將正常工作。不過,您可能確實需要記住一些事情。首先,如果這是一個 TCP 套接字,那麼這仍然是來自對等的單個數據流。
其次,如果您的所有
BeginSend呼叫都發生在同一個執行緒上,那麼結果將是對等方按呼叫順序接收數據。如果您的BeginSend呼叫來自不同的執行緒,那麼數據可能會以任何順序到達,因為每個發送之間可能存在競爭條件。這對您來說可能很重要,也可能無關緊要(取決於您是否在每次發送時發送離散、完整的消息)。第三,如果您使用 TCP 並且發送的速度比套接字另一端的程式碼可以接收的速度快,那麼您可以填充 TCP 視窗並且 TCP 堆棧將開始對您的數據流執行流量控制。如果您繼續發出
BeginSend呼叫,那麼您可能最終會遇到這樣一種情況,即您的回調需要越來越長的時間才能被呼叫,因為伺服器上的 TCP 堆棧將要發送的數據排隊(只有在發送數據並且 TCP基於視窗的流控制將阻止發送新數據,直到 TCP 視窗不再“滿”;即對等方已為某些數據發送了 ACKin flight)。然後,您可能會遇到一種情況,即您正在以一種無法控制的方式耗盡發送機器上的資源(您發出 a
BeginSend並且不知道它何時會完成,並且每次發送都使用記憶體用於正在發送的緩衝區,並且可能non-paged pool在 Winsock 程式碼中關閉…Non-paged pool是系統範圍的資源,在Vista之前的作業系統上非常稀缺,如果低或耗盡,一些表現不佳的驅動程序可能會藍屏框non-paged pool。更重要的是,您還可能將記憶體頁面鎖定到記憶體中,並且還有另一個系統範圍限制鎖定的記憶體頁數。由於這些問題,通常最好實現您自己的協議級別流控制,以限制
BeginSend任何時候可能掛起的呼叫數量(可能使用協議級別 ACK),或者使用 TCP 視窗流控制並使用完成掛起的發送以發出新的發送,您可以在自己的記憶體中排隊發送數據,並且可以完全控制所使用的資源以及如果您排隊“太多”數據時您會做什麼。有關詳細資訊,請參閱我的部落格文章:http ://www.serverframework.com/asynchronousevents/2011/06/tcp-flow-control-and-asynchronous-writes.html請參閱此回复:當 tcp/udp 伺服器發布速度快於客戶端消耗速度時會發生什麼?有關 TCP 視窗流控制的更多資訊以及當您忽略它並發出太多重疊發送時重疊 I/O(在 C++ 領域中)會發生什麼…
總之,發布多個並發
BeginSend呼叫是優化 TCP 數據流的方法,但您需要確保不要發送“太快”,因為一旦發送,您就會以無法控制的方式消耗資源,這是對於執行您的程式碼的機器可能是致命的。因此,不要讓無限數量的BeginSend呼叫未完成,理想情況下,對框進行分析以確保您不會耗盡系統範圍的資源。