关闭和清理Socket连接的正确方式是什么?

22

我对 Socket 对象上数量众多的相关方法感到有些困惑,这些方法据说可以关闭和清理一个 socket 连接。请考虑以下代码:

var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect("192.168.1.22", 8333);
socket.Send(Encoding.UTF8.GetBytes("hello"));

// now for the closing fun
socket.Shutdown(SocketShutdown.Both);
socket.Disconnect(false);
socket.Close();
socket.Dispose();

此外,这位博主指出,要想彻底地关闭一个连接,必须先执行 socket.Shutdown(SocketShudown.Send),然后等待另一端响应。

如何正确地关闭和清理一个 socket 连接?


那个人说的有一半是对的。我认为这取决于两者之间的协议。如果你希望在一段时间内仍然能够接收,那么是的,你应该告诉对方你打算关闭,并说你将停止发送但仍然可以接收。 - uriDium
“那个人”大部分是正确的,因为我已经类似地建模了我的服务器代码。但我认为半关闭再等待的方法只对异步(非阻塞)套接字必要。我相信在非阻塞套接字的情况下,您调用“发送”,然后立即关闭,在某些边缘条件下可能会发生数据丢失,如果有需要重新传输的数据包。 - selbie
我在我的套接字服务器中采用了混合方法。服务器将首先半关闭连接,并等待recv()返回0或错误以指示客户端已完成。但是,我有一个定时器,每45秒定期触发一次,以清除并关闭自上次扫描以来持续存在的任何半开放连接。 - selbie
有没有使用TcpClient的方法来实现这个? - eran otzap
2个回答

18

关闭套接字将关闭连接,Close是Dispose的包装器方法,因此通常

socket.Shutdown(SocketShutdown.Both);
socket.Close();

应该足够了。有人可能会争辩说,Close 实现可能会在某一天发生变化(因此不再调用 Dispose),并且在调用 Close 后手动调用 Dispose,但我个人觉得这不太可能发生 :)

或者,考虑使用 using 语句:

using (var socket = new Socket(...))
{
    ....
    socket.Shutdown(SocketShutdown.Both);
    socket.Close();
}

1
根据MSDN的说法,对于面向连接的套接字,如果您调用Connect,则应调用Close。这也适用于BeginConnectConnectAsync
using (var socket = new Socket(...)) {
    socket.Connect(host);
    ...
    socket.Shutdown(SocketShutdown.Both);
    socket.Close();
}

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