1、翻譯自StackOverflow的推論
This answer made me think I have finally reached some glimpse of an understanding. Then I went testing for a bit and here's the summary of a newbie's view. Please correct me if I'm wrong because this is based on inference, not expertise.
Shutdown
Shutdown
disables the Send
and/or Receive
methods, depending on the provided argument. It doesn't disable the underlying protocol handling and it never blocks.
If Send
is disabled, it also queues up a zero-byte send packet into the underlying send buffer. When the other side receives this packet, it knows that your socket will no longer send any data.
If Receive
is disabled, any data the other side might be trying to send will be lost.
If Receive
is disabled without disabling Send
, it just prevents the socket from receiving data. Since no zero-byte packet will be sent, the other side won't know anything about it until it tries to send something, and only if the socket's protocol requires acknowledging.
Shutdown
禁用了 Send
或者 Receive
方法,具體取決與調用方法時提供的參數。它不會禁用底層的協議處理並且從不造成阻塞。
如果 Send
被禁用,它仍會向底層的發送緩沖中入列一個零字節(zero-byte)數據包。當接收端收到這個數據包時,它將會知道發送端不會再發送任何數據。
如果 Receive
被禁用,發送端嘗試發送的任何數據都會丟失。
如果只禁用了 Receive
但沒有禁用 Send
,那么只會阻止Socket接收數據。因為沒有發出零字節數據包,所以另一端對此不會有任何感知,除非它發送了某些Socket協議要求進行確認的信息。
Disconnect
First, Disconnect
does the equivalent of Shutdown(SocketShutdown.Both)
.
Then it blocks, waiting for two things:
- For all the queued-up send data to be sent.
- For the other side to acknowledge the zero-byte packet (if applicable to the underlying protocol).
If you call Disconnect(false)
, system resources will be freed.
首先,Disconnect
不等同於 Shutdown(SocketShutdown.Both)
。
其次,它會造成阻塞,等待兩件事:
- 所有已入列的數據被發送。
- 另一端確認零字節數據包(如果底層協議適用)。
如果調用了 Disconnect(false)
,系統資源將會被釋放。
Close
Close
frees system resources. May abruptly stop sending queued-up data. If called with the argument, will wait for the data to be sent, but only up to the specified timeout.
Close
會釋放系統資源。它可能會突然停止發送已入列的數據。如果調用此方法時帶有參數,那么他會在指定的超時時間內等待數據發送。
Dispose
Dispose
is same as the Close
overload without the timeout argument. To be more precise, Close
without timeout is the same as Dispose
.
If you use the using
block on the socket, it will automatically call Dispose
.
Dispose
與 Close
的不帶 timeout
參數的重載相同。更准確地講,應該是 Close
的不帶 timeout
參數的重載與 Dispose
相同。
如果對Socket使用了 using
塊,那么將會自動調用 Dispose
。
2、摘錄自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
(true, 參見
Socket.LingerState Property https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.socket.lingerstate?view=netcore-3.1)
並設置 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");