如何在 C# 中检查套接字是否已连接/断开?
如果其他主机在断开连接时没有向您发送数据包(例如,因为它不正常地断开连接),如何检查网络套接字(System.Net.Sockets.Socket)是否仍然连接?
How can you check if a network socket (System.Net.Sockets.Socket) is still connected if the other host doesn't send you a packet when it disconnects (e.g. because it disconnected ungracefully)?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
正如 Paul Turner 回答的那样,
Socket.Connected
在这种情况下不能使用。您需要每次轮询连接以查看连接是否仍然活动。这是我使用的代码:它的工作原理如下:
s.Poll
返回 true 如果s.Available
如果两者都为 true, :As Paul Turner answered
Socket.Connected
cannot be used in this situation. You need to poll connection every time to see if connection is still active. This is code I used:It works like this:
s.Poll
returns true ifs.Available
returns number of bytes available for reading正如 zendar 所写,使用 Socket.Poll 和 Socket 很好。可用,但您需要考虑到套接字可能尚未初始化。这是最后一条信息(我相信),它由 Socket.Connected 属性提供。该方法的修订版本看起来像这样:
As zendar wrote, it is nice to use the
Socket.Poll
andSocket.Available
, but you need to take into consideration that the socket might not have been initialized in the first place. This is the last (I believe) piece of information and it is supplied by theSocket.Connected
property. The revised version of the method would looks something like this:Socket.Connected
属性将告诉您套接字是否认为已连接。它实际上反映了在套接字上执行的最后一次发送/接收操作的状态。如果套接字已被您自己的操作关闭(处置套接字、调用方法来断开连接),
Socket.Connected
将返回false
。如果套接字已通过其他方式断开连接,则该属性将返回true
直到您下一次尝试发送或接收信息,此时将出现SocketException
或ObjectDispositedException
将被抛出。您可以在异常发生后检查该属性,但在发生异常之前它并不可靠。
The
Socket.Connected
property will tell you whether a socket thinks it's connected. It actually reflects the status of the last send/receive operation performed on the socket.If the socket has been closed by your own actions (disposing the socket, calling methods to disconnect),
Socket.Connected
will returnfalse
. If the socket has been disconnected by other means, the property will returntrue
until you next attempt to send or recieve information, at which point either aSocketException
orObjectDisposedException
will be thrown.You can check the property after the exception has occurred, but it's not reliable before.
如果拔掉网线,接受的答案似乎不起作用。或者服务器崩溃。或者你的路由器崩溃了。或者如果您忘记支付互联网账单。设置 TCP 保持活动选项以获得更好的可靠性。
时间值设置自上次发送数据以来的超时时间。然后它尝试发送和接收保持活动数据包。如果失败,它会在指定的时间间隔内重试 10 次(自 Vista AFAIK 以来硬编码的次数),然后再确定连接已失效。
因此上述值将导致 2+10*1 = 12 秒检测。之后,套接字上的任何读取/写入/轮询操作都将失败。
The accepted answer doesn't seem to work if you unplug the network cable. Or the server crashes. Or your router crashes. Or if you forget to pay your internet bill. Set the TCP keep-alive options for better reliability.
The time value sets the timeout since data was last sent. Then it attempts to send and receive a keep-alive packet. If it fails it retries 10 times (number hardcoded since Vista AFAIK) in the interval specified before deciding the connection is dead.
So the above values would result in 2+10*1 = 12 second detection. After that any read / wrtie / poll operations should fail on the socket.
我基于 this 制作了一个扩展方法 MSDN 文章。
这是如何确定套接字是否仍处于连接状态的方法。
I made an extension method based on this MSDN article.
This is how you can determine whether a socket is still connected.
正如 Alexander Logger 在 zendar的回答,你必须发送一些东西才能完全确定。
如果您的关联伙伴
不在此套接字上读取
所有,您可以使用以下
代码。
但即便如此,也可能需要几秒钟的时间才能检测到网络电缆损坏或类似情况。
As Alexander Logger pointed out in zendars answer, you have to send something to be completely sure.
In case your connected partner
does not read on this socket at
all, you can use the following
code.
But even then it might take a few seconds until a broken network cable or something similar is detected.
遵循 NibblyPig 和 的建议zendar,我想出了下面的代码,它适用于我所做的每个测试。我最终需要 ping 和 poll。 ping 将让我知道电缆是否已断开,或者物理层是否已中断(路由器断电等)。但有时重新连接后我会收到 RST,ping 正常,但 tcp 状态却不行。
Following the advice from NibblyPig and zendar, I came up with the code below, which works on every test I made. I ended up needing both the ping, and the poll. The ping will let me know if the cable has been disconnected, or the physical layer otherwise disrupted (router powered off, etc). But sometimes after reconnect I get a RST, the ping is ok, but the tcp state is not.
最好的方法就是让您的客户端每 X 秒发送一次 PING,并且服务器在一段时间内没有收到 PING 消息后假设它已断开连接。
我在使用套接字时遇到了与您相同的问题,这是我能做到的唯一方法。 socket.connected 属性从来都不正确。
但最终,我转而使用 WCF,因为它比套接字可靠得多。
The best way is simply to have your client send a PING every X seconds, and for the server to assume it is disconnected after not having received one for a while.
I encountered the same issue as you when using sockets, and this was the only way I could do it. The socket.connected property was never correct.
In the end though, I switched to using WCF because it was far more reliable than sockets.
只需像 @toster-cx 所说的那样使用 KeepAlive,然后使用 Socket Connected 状态来检查 Socket 是否仍处于连接状态。将接收超时设置为与保持连接超时相同。如果您有更多问题,我很乐意为您提供帮助!
Just use the KeepAlive like @toster-cx says and then use the Socket Connected status to check if the Socket is still connected. Set your receive timeout at the same timeout of the keepalive. If you have more questions i am always happy to help!
使用Socket.Connected
属性。--更新--
正如 Paul Turner 所回答的那样,在这种情况下不能使用 Socket.Connected 。您需要每次轮询连接以查看连接是否仍然活动。请参阅2
UseSocket.Connected
Property.--UPDATE--
As Paul Turner answered Socket.Connected cannot be used in this situation. You need to poll connection every time to see if connection is still active. See 2