socket的Shutdown、Disconnect、Close和Dispose分别具有什么作用?

36

很难找到一份简单明了的解释,专门为网络编程新手讲解这四种方法,它们实际上是做什么的。人们通常只陈述在特定场景下关闭套接字的正确方式,但不说每个步骤背后发生了什么。

按照授人以鱼不如授人以渔的哲学,你能解释一下ShutdownDisconnectCloseDispose这四种方法吗?


1
我发现,如果你正在等待数据仍在传输中,仅调用Shutdown是不够的。在调用Disconnect或Close之前,你可能需要手动Sleep(直到我找到更好的方法)一小段时间。 - Brain2000
你看了我的回答吗?如果我没错的话,Shutdown不会等待数据被发送。此外,调用没有参数的Close(或Dispose,它们是相同的),将会突然停止发送数据。Disconnect应该会阻塞,直到所有剩余的数据都被发送。或者,使用带有超时的Close也会在给定时间内等待,然后突然停止传输。 - relatively_random
1
我已经看过你的回答,但在我的情况下它并没有起作用。我想知道网卡驱动程序是否与这种行为有关。即使设置了Linger,有时数据也无法发送。我认为Windows堆栈存在一些关闭错误,而微软的文档又很少且过时。 - Brain2000
1个回答

48

这个回答在StackOverflow上让我觉得我终于有了一些了解。然后我进行了一些测试,以下是一个新手的总结。如果我理解错了,请纠正我,因为这是基于推论而非专业知识。

关闭连接

Shutdown方法禁用Send和/或Receive方法,具体取决于提供的参数。它不会禁用底层协议处理并且永远不会阻塞。

如果禁用了Send,它会将一个零字节的发送包排队到底层发送缓冲区中。当对方接收到该包时,它就知道你的套接字将不再发送任何数据。

如果禁用了Receive,则对方可能正在尝试发送的任何数据都将丢失。

如果禁用了Receive但没有禁用Send,它只会阻止套接字接收数据。由于不会发送零字节数据包,所以只有在对方尝试发送数据且套接字的协议要求确认时,对方才会知道它。

断开连接

首先,Disconnect执行相当于Shutdown(SocketShutdown.Both)的操作。

然后,它会阻塞等待两件事情:

  1. 所有排队的发送数据都已发送。
  2. 对方确认了零字节数据包(如果适用于底层协议)。

如果调用Disconnect(false),系统资源将被释放。

关闭套接字

Close方法释放系统资源。可能会突然停止发送排队的数据。如果带参数调用,则最多等待指定的超时时间来发送数据。

释放资源

Dispose 相当于没有超时参数的 Close 重载。更准确地说,没有超时的 CloseDispose 是相同的。

如果您在套接字上使用 using 块,它将自动调用 Dispose


如果您要进行规范问题,您可能还希望在最后链接到其他现有的帖子,并确保链接到 MSDN 文档。否则看起来不错。 - Alexei Levenkov
断开连接似乎有问题。我怀疑它是否等待所有数据被确认。文档说:“为确保在关闭套接字之前发送和接收所有数据,应在调用Disconnect方法之前调用Shutdown。”。此外,我一直认为Shutdown会等待确认,但现在不再100%确定。Linger选项似乎控制着这两种方法所做的操作,因此对于某些Linger选项,这个答案实际上可能是正确的。 - usr
@usr 说得好。那么,Disconnect 实际上是做什么的?它相当于 Close 并具有重用资源的能力吗? - relatively_random
我相信是这样的,但我很惊讶在文档中读到它有时会阻塞并等待确认。 - usr
3
@usr 在 BeginDisconnect 页面上的示例是完全异步的,并且在调用 BeginDisconnect 之前使用 Shutdown。我得出的结论是 Disconnect 是阻塞的。这是关于套接字最令人沮丧的事情:文档并不十分清楚正在发生什么。https://msdn.microsoft.com/zh-cn/library/system.net.sockets.socket.begindisconnect(v=vs.110).aspx - relatively_random
这是有趣的证据。到目前为止,我还没有读过任何权威的文章来解释Shutdown和Disconnect究竟是做什么的。 - usr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接