2013-01-15 36 views
2

你們許多人都知道原來的「send()」不會寫入你要求的字節數。很容易,您可以使用指針和循環來確保您的數據全部發送。在完成端口中調用WSASend()?

但是,我沒有看到WSA​​Send()和完成端口如何在這種情況下工作。它立即返回,並且您無法控制發送的數量(除了在例程中可訪問的lpLength外)。這是如何解決的?

您是否必須多次調用例程中的WSASend()才能獲取所有數據?這看起來不是一個很大的缺點,特別是如果你想以特定的順序輸出數據並且多個線程訪問例程?

回答

0

首先關於send。實際上可能會發生2種不同的事情,這取決於套接字是如何配置的。

如果插座是在所謂的阻塞模式(缺省) - 調用send調用線程,直到所有的輸入緩衝器由底層網絡驅動器所消耗。 (請注意,這並不意味着數據已經到達對端)。

如果套接字被轉移到非阻塞模式 - 如果底層驅動程序可能不會立即消耗所有輸入,則調用send失敗。在這種情況下,GetLastError返回WSAEWOULDBLOCK。應用程序應該等到它可能重試發送。而不是在循環中調用send,應用程序應該從系統獲取有關套接字狀態更改的通知。諸如WSAEventSelectWSAAsyncSelect之類的函數可以用於此(以及傳統select)。

現在,隨着I/O完成端口和WSASend的故事有所不同。當套接字與完成端口關聯時 - 它會自動轉換到非阻塞模式。

如果到WSASend呼叫不能立即完成(即網絡驅動程序不能消耗所有的輸入) - 的WSASend返回一個錯誤並GetLastError返回STATUS_PENDING。這實際上意味着異步操作已啓動但尚未完成**。

也就是說,您不應該重複調用WSASend,因爲發送操作已經在進行中。當它完成時(無論是否成功),您將在I/O完成端口上獲得通知,但同時調用線程可以自由地執行其他操作。

+0

但是,如果WSASend()中的緩衝區已消耗但尚未到達對等點,但IO會告訴您它已發送所有內容。那又怎麼樣? – user1255454

+0

當套接字驅動程序已經完成接收所有請求的數據並準備好接受更多數據時,您會收到通知。這並不意味着數據實際上已經傳輸到對等端了。例如,如果您沒有在套接字上禁用Nagle算法,那麼當緩衝區有足夠的數據發送更高效的網絡數據包時,數據將被複制到內部緩衝區中並在後臺傳輸。一旦套接字已經接受你的數據,不管它是否立即傳輸,它都不在你的手中。繼續前進並做其他事情。 –

2

WSASend()在完成端口不會通知您,直到所有請求的數據已被套接字接受,或者直到發生錯誤(以先發生者爲準)。它在後臺繼續工作,直到所有數據都被接受(或錯誤)。在通知您之前,緩衝區必須在內存中保持活動狀態,但您的代碼可以自由地繼續執行其他任務,而WSASend()正忙碌。數據實際傳輸給對等方時沒有通知。如果你需要,那麼你必須在你的數據協議中實現一個ACK,這樣對方可以在收到數據時通知你。

6

當您使用與IOCPOVERLAPPED結構關聯的套接字調用WSASend時,您可以將數據有效地傳遞到網絡堆棧以發送。一旦您使用的數據緩衝區不再需要網絡堆棧,網絡堆棧將爲您提供「完成」。此時,您可以自由重複使用或釋放​​用於數據緩衝區的內存。

請注意,數據不太可能在生成完成點到達對等點,並且完成的生成意味着網絡堆棧已經佔用了緩衝區內容的所有權。

這與send的操作方式不同。在send處於阻止模式時,將阻止對send的呼叫,直到網絡堆棧使用您提供的所有數據。對於在非阻塞模式下調用send,網絡堆棧從緩衝區獲取儘可能多的數據,然後返回給您關於它使用量的詳細信息;這意味着您的一些數據已被使用。通常在WSASend之前,您的所有數據都會在您收到通知之前使用。

重疊的WSASend可能因資源限制或網絡錯誤而失敗。發生失敗表明一些數據已經發送但不是全部是很常見的。通常它都發送OK或根本沒有發送。然而,可能會得到一個錯誤的完成,表明有些數據已被使用,但並非全部。從這一點開始的過程取決於錯誤(臨時資源限制或硬網絡故障)以及您在該套接字上掛起的其他多少個其他WSASend(零或非零)。如果您有臨時資源錯誤並且沒有其他未完成的WSASend調用此套接字,則只能嘗試發送其餘數據;由於您不知道臨時資源限制情況何時會通過,所以這會變得更加複雜......如果您有暫時的資源限制導致部分發送,並且您還有其他WSASend調用等待中,那麼您應該中止該連接可能會通過從此WSASend調用發送部分緩衝區,然後調用後續的所有(或部分)WSASend調用來混淆數據流。

請注意,它是a)有用的和b)在套接字上有多個未調用的WSASend調用。這是保持連接充分利用的唯一方法。但是,您應該意識到存在多次重疊WSASend調用(請參見here)的內存和資源使用含義,因爲您有效地控制了緩衝區的生命週期(並因此控制了內存和資源的數量由於TCP流量控制問題,您的代碼使用)到對端)。請參閱SIO_IDEAL_SEND_BACKLOG_QUERYSIO_IDEAL_SEND_BACKLOG_CHANGE如果您想真正聰明......

相關問題