.net 如何在 C# 中检查(TCP)套接字是否已(断开)连接?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/515458/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I check whether a (TCP) socket is (dis)connected in C#?
提问by Hosam Aly
How should I check a (TCP) socket to find out whether it is connected?
我应该如何检查(TCP)套接字以确定它是否已连接?
I have read about the Socket.Connectedproperty in MSDN, but it says it only shows the state according to the last I/O. This isn't useful for me, since I want to do this beforetrying to read from the socket. The remarks section also notes that:
我已经阅读了MSDN 中的Socket.Connected属性,但它说它只显示根据最后一个 I/O 的状态。这对我没有用,因为我想在尝试从套接字读取之前执行此操作。备注部分还指出:
If you need to determine the current state of the connection, make a nonblocking, zero-byte Send call. If the call returns successfully or throws a WAEWOULDBLOCK error code (10035), then the socket is still connected; otherwise, the socket is no longer connected.
如果需要确定连接的当前状态,请进行非阻塞的零字节 Send 调用。如果调用成功返回或抛出 WAEWOULDBLOCK 错误代码(10035),则套接字仍处于连接状态;否则,套接字不再连接。
The example on the same page shows how to do it.(1)But a post by Ian Griffithssays that I should readfrom the socket, not sendthrough it.
同一页面上的示例显示了如何执行此操作。(1)但是Ian Griffiths 的一篇文章说我应该从套接字读取,而不是通过它发送。
Another post by Pete Dunihosays:
... after you've called
Shutdown(), callReceive()until it returns0(assuming the remote endpoint isn't actually going to send you anything, that will happen as soon as the remote endpoint has received all of your data). Unless you do that, you have no assurance that the remote endpoint has actually received all of the data you sent, even using a lingering socket.
...在您调用之后
Shutdown(),调用Receive()直到它返回0(假设远程端点实际上不会向您发送任何内容,一旦远程端点收到您的所有数据,就会发生这种情况)。除非您这样做,否则您无法保证远程端点实际上已收到您发送的所有数据,即使使用延迟套接字也是如此。
I don't really understand his statement about calling Receive()to make sure that the remote endpoint has actually received all the data I sent. (Do sockets block receiving until the sending buffer is empty?)
我不太明白他关于调用Receive()以确保远程端点实际上已收到我发送的所有数据的声明。(套接字是否会阻止接收,直到发送缓冲区为空?)
I am confused by the different methods proposed. Could you please explain them?
我对提出的不同方法感到困惑。你能解释一下吗?
(1) I wonder why the examplefor the Socket.Connectedproperty allocates a 1-byte array, even though it calls Sendwith 0 length?
(1)但不知为何,例如为Socket.Connected属性分配1字节的数组,即使它调用Send与0长度?
采纳答案by Quassnoi
Death of a socket changes its behavior in several ways, so these methods are both valid :)
套接字的死亡会以多种方式改变其行为,因此这些方法都是有效的 :)
With both methods you actually check those parts of the socket's behavior that change after disconnection.
使用这两种方法,您实际上可以检查那些在断开连接后发生变化的套接字行为部分。
I don't really understand his statement about calling Receive() to make sure that the remote endpoint has actually received all the data I sent. (Do sockets block receiving until the sending buffer is empty?)
我不太明白他关于调用 Receive() 以确保远程端点实际上已收到我发送的所有数据的声明。(套接字是否会阻止接收,直到发送缓冲区为空?)
TCPis reliable protocol, that means that every packet you send must be acknowledged. Acknowledgement implies sending the packets with ACKbit set. These packets may or may not contain additional (payload) data.
TCP是可靠的协议,这意味着您发送的每个数据包都必须得到确认。确认意味着发送带有ACK位设置的数据包。这些数据包可能包含也可能不包含附加(有效载荷)数据。
When the socket is connected, Receive()will block until the socket receives a packet with non-empty payload. But when the socket is disconnected, Receive()will return as soon as the last ACKpacket arrives.
当套接字连接时,Receive()将阻塞,直到套接字接收到具有非空负载的数据包。但是当socket断开时,Receive()会在最后一个ACK数据包到达时立即返回。
Calling Receive()ensures that you either receivethat last ACKpacket from your remote endpoint or a disconnect timeout occurs and you will be able to receivenothing more on this socket.
调用Receive()确保您要么从远程端点接收最后一个ACK数据包,要么发生断开连接超时,并且您将无法在此套接字上接收更多信息。
The example on the same page shows how to do it. (I wonder why does it allocate a 1-byte array, even though it calls Send with 0 length?) But a post by Ian Griffiths says that I should read from the socket, not send through it.
同一页面上的示例显示了如何执行此操作。(我想知道为什么它分配一个 1 字节的数组,即使它以 0 长度调用 Send?)但是 Ian Griffiths 的一篇文章说我应该从套接字读取,而不是通过它发送。
When send()ing to a socket, you actually try to append some data to the end of the socket queue. Is there is some place left in the buffer, then your Send()returns instantly, if not, the Send()blocks until there is some place.
当send()ing 到套接字时,您实际上尝试将一些数据附加到套接字队列的末尾。缓冲区中是否还有一些位置,然后您Send()立即返回,如果没有,则Send()阻塞直到有某个位置。
When the socket is in disconnected state, TCP/IPstack prevents all further operations with the buffer, that's why Send()returns an error.
当套接字处于断开连接状态时,TCP/IP堆栈会阻止对缓冲区的所有进一步操作,这就是Send()返回错误的原因。
Send()implements a basic pointer check, this means it fails when a NULLpointer is passed to it. You may probably pass any non-null constant as a pointer, but you better allocate 1 byte instead of making the constant up — just in case.
Send()实现了一个基本的指针检查,这意味着当一个NULL指针传递给它时它会失败。您可能会将任何非空常量作为指针传递,但您最好分配 1 个字节而不是将常量组合起来——以防万一。
You may use any method you like, as none of them is resource consuming. As long as they are used for socket connection checking, they are identical.
您可以使用任何您喜欢的方法,因为它们都不消耗资源。只要它们用于套接字连接检查,它们都是相同的。
As for me, I would prefer Receive(), as this is what you normally run in a cycle and wait for. You get a non-zero from Receive(), you process data; you get a zero, you process disconnection.
至于我,我更喜欢Receive(),因为这是您通常在一个循环中运行并等待的内容。你从 中得到一个非零值Receive(),你处理数据;你得到一个零,你处理断开连接。
回答by loaf of bread
"If you need to determine the current state of the connection, make a nonblocking, zero-byte Send call. If the call returns successfully or throws a WAEWOULDBLOCK error code (10035), then the socket is still connected; otherwise, the socket is no longer connected." -- unfortunately, it doesn't even work!
"如果需要确定连接的当前状态,请进行非阻塞、零字节的 Send 调用。如果调用成功返回或抛出 WAEWOULDBLOCK 错误代码 (10035),则表示套接字仍处于连接状态;否则,套接字处于连接状态不再连接。” ——不幸的是,它甚至不起作用!
mySocket.Blocking = false;
byte[] buffer = new byte[1];
int iSent = mySocket.Send(buffer, 0, SocketFlags.None);
bConnected = mySocket.Connected;
bConnected always ends up as true, and the call always returns successfully, even though the Ethernet cable has been unplugged.
bConnected 总是以真结束,并且呼叫总是成功返回,即使以太网电缆已被拔出。
Moreover, and unfortunately == sending any actual data doesn't detect the broken connection, either.
此外,不幸的是 == 发送任何实际数据也不会检测到断开的连接。
buffer[0] = 0xff ;
int iSent = mySocket.Send(buffer, 1, SocketFlags.None);
repeatedly returns 1, as if if had actually sent something. While the device in question isn't even connected any more.
重复返回 1,就好像真的发送了什么一样。虽然有问题的设备甚至不再连接。
回答by user207421
I don't really understand his statement about calling Receive() to make sure that the remote endpoint has actually received all the data I sent.
我不太明白他关于调用 Receive() 以确保远程端点实际上已收到我发送的所有数据的声明。
The post by @PeteDuniho isn't about establishing the state of the connection, it is about terminating the connection in such a way that you know when the peer has received all your data.
@PeteDuniho 的帖子不是关于建立连接的状态,而是关于以这样一种方式终止连接,即您知道对等方何时收到了您的所有数据。
(Do sockets block receiving until the sending buffer is empty?)
(套接字是否会阻止接收,直到发送缓冲区为空?)
No, but if you shutdown the socket and then read until EOS, you are waiting for the peer to read all the data until hegets EOS and then closes the socket. So you have a guarantee that all the data has got into the peer application.
不是,但是如果你关闭socket然后读到EOS,你就是在等待peer读取所有数据,直到他拿到EOS然后关闭socket。因此,您可以保证所有数据都已进入对等应用程序。
回答by ng5000
Typically one would use the Socket.Select method to determine the state of a set of sockets (Socket.Poll for a single socket).
通常,人们会使用 Socket.Select 方法来确定一组套接字的状态(Socket.Poll 用于单个套接字)。
Both of these methods allow you to query a socket's state. Now, assuming that you have tracked that the socket connected in the first place then you would typically call Select/Poll on the socket before attempting a read. If Select/Poll indicate that the socket is readable this tells you that:
这两种方法都允许您查询套接字的状态。现在,假设您已经跟踪到首先连接的套接字,那么您通常会在尝试读取之前在套接字上调用 Select/Poll。如果 Select/Poll 指示套接字是可读的,这告诉您:
- Either the socket has data available top read in which case Receive will return the data available to read.
- The socket socket has been closed, in which case when you call Receive 0 bytes will be returned immediately (i.e. If Select/Poll indicate that the socket is readable and you call Receive but it returns immediately with 0 bytes then you know that the connection has either been Closed, Reset or Terminated.
- 要么套接字有数据可用顶部读取,在这种情况下 Receive 将返回可读取的数据。
- 套接字套接字已关闭,在这种情况下,当您调用 Receive 时,将立即返回 0 个字节(即,如果 Select/Poll 指示套接字是可读的并且您调用了 Receive 但它立即返回了 0 个字节,则您知道该连接已已关闭、重置或终止。
Personally I've never used Poll - I've always used Select but MSDN seems to suggest that Poll is pretty much the same as Select but for single sockets.
就我个人而言,我从未使用过 Poll - 我一直使用 Select 但 MSDN 似乎表明 Poll 与 Select 几乎相同,但用于单个套接字。
I'll also add that in most cases using Select is the most efficient and best way of handling Socket connections.
我还要补充一点,在大多数情况下,使用 Select 是处理 Socket 连接的最有效和最好的方法。

