C# Socket類中Shutdown、Close、Disconnect、Dispose方法的區別

C# Socket類中Shutdown、Close、Disconnect、Dispose方法的區別


摘錄自MSDN的API說明

原文:https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.socket

Shutdown

禁用Socket的發送和/或接收功能,具體取決於提供給方法的參數。

當使用面向連接的Socket時,關閉Socket前總是應該先調用 Shutdown() 方法。這能夠確保在已連接的Socket關閉前,其上的所有數據都發送和接收完成。然後調用 Close() 方法來釋放此Socket相關的託管和未託管資源,在關閉後不要嘗試複用此Socket。

調用方法時提供 SocketShutdown.Send 參數將會禁止後續對 Send() 方法的調用。如果正在使用無連接的Socket,指定此參數不會產生任何影響。

調用方法時提供 SocketShutdown.Receive 參數將會禁止後續對 Receive() 方法的調用。這一操作對較低的協議層無效。如果正在使用面向連接的協議,調用了 Shutdown() 方法後,在下列任一一種狀態退出時,連接會被終止:

  • 在傳入網絡緩衝區(incoming network buffer)中的數據正等待接收。
  • 到達了更多的數據。

如果正在使用無連接的協議,數據報會被接受和排隊。然而,如果對於正在接收的額外數據報沒有可用的緩衝空間,這些數據報將會被丟棄,並且不會向發送者返回任何錯誤信息。不建議對無連接的Socket使用 Shutdown() 方法。

Disconnect

關閉Socket連接,並根據提供給方法的參數決定是否允許重用實例。

如果正在使用面向連接的協議,可以使用 Disconnect() 方法來關閉Socket。這一方法會結束連接並將Socket對象的 Connected 屬性設置爲 false 。然而,如果提供的 reuseSocket 參數爲 true ,則可以重用Socket對象。

爲確保在Socket關閉前所有數據都已發送和接收完成,應該在調用 Disconnect() 方法前調用 Shutdown() 方法

如果需要在調用 Disconnect() 方法時不先行調用 Shutdown() 方法,應該將 DontLingerSocket 選項設置爲 false 並指定一個非零的超時間隔,以確保已排隊準備向外發送的數據發送完成。之後 Disconnect() 方法會阻塞直到數據發送完成或者超時。如果將 DontLinger 設爲 false 並設置 0 爲超時間隔,Close() 方法會釋放連接並自動拋棄已排隊準備向外發送的數據。

Close

關閉Socket連接並釋放所有相關資源,另外提供一個帶有參數的重載來允許在指定的超時時間內將已經排隊的數據發送出去。

Close() 方法會關閉遠程主機連接,並釋放所有與此Socket相關的託管資源和未託管資源。關閉後,Socket對象的 Connected 屬性會設置爲 false

對於面向連接的協議,建議在調用 Close() 方法前先調用 Shutdown() 方法。這能夠確保在已連接的Socket關閉前,其上的所有數據都發送和接收完成。

如果需要在調用 Close() 方法時不先行調用 Shutdown() 方法,可以將 DontLingerSocket 選項設置爲 false 並指定一個非零的超時間隔,以確保已排隊準備向外發送的數據發送完成。之後 Disconnect() 方法會阻塞直到數據發送完成或者超時。如果將 DontLinger 設爲 false 並設置 0 爲超時間隔,Close() 方法會釋放連接並自動拋棄已排隊準備向外發送的數據。

Dispose

釋放當前Socket實例所使用的未託管資源,並且提供可選操作來釋放當前Socket實例所使用的託管資源。

在結束使用Socket時調用 Dispose() 方法,該方法會使Socket處於一種不可用狀態。在調用 Dispose() 方法後,必須釋放對Socket對象的所有引用,以便垃圾回收器回收被Socket對象佔用的內存。

在釋放對Socket對象的最後一個引用前總是應該調用 Dispose() 方法。否則,在垃圾回收器調用Socket對象的 Finalize() 方法前,Socket對象所使用的資源無法被釋放。


總結:在停止使用Socket時,都應該先調用 Shutdown() 方法,以確保所有數據都發送和接收完成。儘量使用 using 塊處理Socket對象,這樣在結束使用Socket時,只需調用 Shutdown() 方法即可,系統會自動釋放資源。

using(var socket = new Socket())
{
	// do something
	// ...
	socket.Shutdown(SocketShutdown.Both);
}

官方提供的一些示例代碼中,在停止使用Socket對象時都先調用了 Shutdown() 方法:

sender.Shutdown(SocketShutdown.Both);  
sender.Close();  

從官方的另一段示例代碼可以看出,對Socket對象調用了 Disconnect() 方法後,並不一定會立即斷開連接,在此推測Socket對象會等待正在進行中的數據發送或接收操作。

client.Shutdown(SocketShutdown.Both);
client.Disconnect(true);
if (client.Connected) 
    Console.WriteLine("We're still connnected");
else 
    Console.WriteLine("We're disconnected");

翻譯自StackOverflow的推論

原文:https://stackoverflow.com/questions/35229143/what-exactly-do-sockets-shutdown-disconnect-close-and-dispose-do

ShutdownShutdown 禁用了 Send 或者 Receive 方法,具體取決與調用方法時提供的參數。它不會禁用底層的協議處理並且從不造成阻塞。

如果 Send 被禁用,它仍會向底層的發送緩衝中入列一個零字節(zero-byte)數據包。當接收端收到這個數據包時,它將會知道發送端不會再發送任何數據。

如果 Receive 被禁用,發送端嘗試發送的任何數據都會丟失。

如果只禁用了 Receive 但沒有禁用 Send ,那麼只會阻止Socket接收數據。因爲沒有發出零字節數據包,所以另一端對此不會有任何感知,除非它發送了某些Socket協議要求進行確認的信息。

Disconnect:首先,Disconnect 不等同於 Shutdown(SocketShutdown.Both)

其次,它會造成阻塞,等待兩件事:

  1. 所有已入列的數據被髮送。
  2. 另一端確認零字節數據包(如果底層協議適用)。

如果調用了 Disconnect(false) ,系統資源將會被釋放。

CloseClose 會釋放系統資源。它可能會突然停止發送已入列的數據。如果調用此方法時帶有參數,那麼他會在指定的超時時間內等待數據發送。

DisposeDisposeClose 的不帶 timeout 參數的重載相同。更準確地講,應該是 Close 的不帶 timeout 參數的重載與 Dispose 相同。

如果對Socket使用了 using 塊,那麼將會自動調用 Dispose

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章