C#中Socket關閉 Close、Dispose、Shutdown、Disconnect


1、翻譯自StackOverflow的推論

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

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:

  1. For all the queued-up send data to be sent.
  2. 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) 。

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

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

如果調用了 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, Closewithout 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");


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM