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的推論
Shutdown:Shutdown
禁用了 Send
或者 Receive
方法,具體取決與調用方法時提供的參數。它不會禁用底層的協議處理並且從不造成阻塞。
如果 Send
被禁用,它仍會向底層的發送緩衝中入列一個零字節(zero-byte)數據包。當接收端收到這個數據包時,它將會知道發送端不會再發送任何數據。
如果 Receive
被禁用,發送端嘗試發送的任何數據都會丟失。
如果只禁用了 Receive
但沒有禁用 Send
,那麼只會阻止Socket接收數據。因爲沒有發出零字節數據包,所以另一端對此不會有任何感知,除非它發送了某些Socket協議要求進行確認的信息。
Disconnect:首先,Disconnect
不等同於 Shutdown(SocketShutdown.Both)
。
其次,它會造成阻塞,等待兩件事:
- 所有已入列的數據被髮送。
- 另一端確認零字節數據包(如果底層協議適用)。
如果調用了 Disconnect(false)
,系統資源將會被釋放。
Close:Close
會釋放系統資源。它可能會突然停止發送已入列的數據。如果調用此方法時帶有參數,那麼他會在指定的超時時間內等待數據發送。
Dispose:Dispose
與 Close
的不帶 timeout
參數的重載相同。更準確地講,應該是 Close
的不帶 timeout
參數的重載與 Dispose
相同。
如果對Socket使用了 using
塊,那麼將會自動調用 Dispose
。