如何在.NET中重用socket?

17

我正在尝试重新连接到一个已经断开连接的套接字,但出于某种原因它不允许这样做,即使我使用参数"reuseSocket"将Disconnect方法调用设置为true。

_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_socket.Connect(ipAddress, port);
//...receive data
_socket.Disconnect(true); //reuseSocket = true
//...wait
_socket.Connect(ipAddress, port); //throws an InvalidOperationException:

一旦socket断开连接,你只能异步重新连接到不同的EndPoint。必须在等待操作完成之前不退出的线程上调用BeginConnect。

我做错了什么?


可能最好不要重复使用套接字,而是创建一个新的。永远不要调用 Disconnect,而是将其包装在 using 中。此外,调用 Shutdown - usr
4个回答

8
您可以像这样设置套接字选项。
_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, True)

如果不起作用,尝试其他选项。
_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, false)
_Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, True)
_Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 500)
_Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, Timeout)

4
阅读了 Socket.Disconnect 的 MSDN 文档后,我注意到可能会导致您问题的内容。

如果您需要在不先调用 Shutdown 的情况下调用 Disconnect,则可以将名为 SocketOption 的选项设置为 DontLingerfalse 并指定非零超时间隔,以确保已排队的传出数据被发送。 然后,Disconnect 将阻塞,直到数据被发送或指定的超时时间到期。如果您将 DontLinger 设置为 false 并指定零超时间隔,则 Close 会释放连接并自动丢弃传出的排队数据。

请尝试设置 DontLinger Socket 选项并指定 0 超时,或在调用 disconnect 之前使用 Shutdown

2
有趣的是,没有名为“DontLingerSocket”的属性或方法。最接近它的是一个叫做“LingerState”的属性。你可以实例化一个“LingerOption”并将其设置为它,但如果你在调用“Disconnect”之后尝试重新连接,它并没有任何不同。如果你调用“Close”,你就不能重用一个socket,因为那会处理这个socket。 - user65199
那里少了一个空格,它应该是两个单词"Don'tLinger"和"Socket"。更好的表述方式是*"...在调用Shutdown时,您可以将名为Don'tLingerSocketOption设置为false,并指定非零值....."* - Scott Chamberlain
@ScottChamberlain 已经注意到了。 - James
2
有一个“DontLinger”选项和一个“Linger”选项。所以如果DontLinger应该是false,那么Linger应该是true。你只需要设置其中一个还是两个都需要设置?我感觉设计这个的人在吸毒。 - Brain2000

1

你尝试在断开连接后,在连接之前添加这行代码了吗?

client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

0

来自MSDN

// Release the socket.
client.Shutdown(SocketShutdown.Both);

client.Disconnect(true);
if (client.Connected) 
    Console.WriteLine("We're still connnected");
else 
    Console.WriteLine("We're disconnected");

如果您正在使用面向连接的协议,则可以使用此方法来关闭套接字。该方法会结束连接并将Connected属性设置为false。但是,如果reuseSocket为true,则可以重用套接字。
在调用Disconnect方法之前,应调用Shutdown方法以确保在关闭套接字之前发送和接收所有数据。
Socket.Shutdown方法会等待缓冲区中的所有数据都已发送或接收。然而,如果我们只设置了延迟选项,那么套接字将在一定的超时时间后关闭。

1
@Hermann:我认为你需要等待一些时间(超时)让套接字变得“可重用”,你可以尝试将套接字放入线程中进行重试...只是思考一下;更多关于“优雅关闭”的信息,请阅读http://msdn.microsoft.com/en-us/library/ms738547(VS.85).aspx - KMån
1
请注意:client.Connected 定义为最近一次 SendReceive 的连接状态,而不是当前状态。由于您刚调用了 Disconnect,因此消息应该是 "我们曾经连接过""我们没有连接" - Jesse Chisholm

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