原文: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 会释放系统资源。它可能会突然停止发送已入列的数据。如果调用此方法时带有参数,那么他会在指定的超时时间内等待数据发送。

DisposeDispose 与 Close 的不带 timeout 参数的重载相同。更准确地讲,应该是 Close 的不带 timeout 参数的重载与 Dispose 相同。

如果对Socket使用了 using 块,那么将会自动调用 Dispose 。

以上原文来自csdn:https://blog.csdn.net/qq_21397217/article/details/96176962

作者 申佳明

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

Captcha Code