如何在C#中检查(dis)连接(TCP)套接字?

时间:2021-02-18 07:22:09

How should I check a (TCP) socket to find out whether it is connected?

我应该如何检查(TCP)套接字以确定它是否已连接?

I have read about the Socket.Connected property 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 before trying 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.

如果需要确定连接的当前状态,请进行非阻塞,零字节发送调用。如果调用成功返回或抛出WAEWOULDBLOCK错误代码(10035),则套接字仍然连接;否则,套接字不再连接。

The example on the same page shows how to do it.(1) But a post by Ian Griffiths says that I should read from the socket, not send through it.

同一页面上的例子显示了如何做到这一点。(1)但Ian Griffiths的帖子说我应该从套接字读取,而不是通过它发送。

Another post by Pete Duniho says:

Pete Duniho的另一篇文章说:

... after you've called Shutdown(), call Receive() until it returns 0 (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 example for the Socket.Connected property allocates a 1-byte array, even though it calls Send with 0 length?

(1)我想知道为什么Socket.Connected属性的例子分配一个1字节的数组,即使它调用0长度的Send?

4 个解决方案

#1


21  

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()的说法,以确保远程端点实际上已收到我发送的所有数据。 (套接字阻塞接收,直到发送缓冲区为空?)

TCP is reliable protocol, that means that every packet you send must be acknowledged. Acknowledgement implies sending the packets with ACK bit 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 ACK packet arrives.

连接套接字时,Receive()将阻塞,直到套接字收到具有非空有效负载的数据包。但是当套接字断开连接时,一旦最后一个ACK数据包到达,Receive()就会返回。

Calling Receive() ensures that you either receive that last ACK packet from your remote endpoint or a disconnect timeout occurs and you will be able to receive nothing 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长度的发送?)但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()转到套接字时,实际上会尝试将一些数据附加到套接字队列的末尾。缓冲区中是否还有一些地方,那么Send()会立即返回Send()块,直到有一些地方为止。

When the socket is in disconnected state, TCP/IP stack 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 NULL pointer 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()得到一个非零,你处理数据;你得到零,你处理断开连接。

#2


4  

"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!

“如果你需要确定连接的当前状态,请进行非阻塞,零字节发送调用。如果调用成功返回或抛出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始终为true,即使已拔下以太网电缆,呼叫也始终成功返回。

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,好像是否已经发送了一些东西。虽然有问题的设备甚至不再连接。

#3


1  

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.
  • 套接字可以在顶部读取数据,在这种情况下,Receive将返回可读取的数据。
  • 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 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.

我个人从未使用过民意调查 - 我一直使用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连接的最有效和最好的方法。

#4


1  

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 he gets EOS and then closes the socket. So you have a guarantee that all the data has got into the peer application.

不,但如果您关闭套接字然后读取直到EOS,您正在等待对等方读取所有数据,直到他获得EOS然后关闭套接字。因此,您可以保证所有数据都已进入对等应用程序。

#1


21  

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()的说法,以确保远程端点实际上已收到我发送的所有数据。 (套接字阻塞接收,直到发送缓冲区为空?)

TCP is reliable protocol, that means that every packet you send must be acknowledged. Acknowledgement implies sending the packets with ACK bit 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 ACK packet arrives.

连接套接字时,Receive()将阻塞,直到套接字收到具有非空有效负载的数据包。但是当套接字断开连接时,一旦最后一个ACK数据包到达,Receive()就会返回。

Calling Receive() ensures that you either receive that last ACK packet from your remote endpoint or a disconnect timeout occurs and you will be able to receive nothing 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长度的发送?)但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()转到套接字时,实际上会尝试将一些数据附加到套接字队列的末尾。缓冲区中是否还有一些地方,那么Send()会立即返回Send()块,直到有一些地方为止。

When the socket is in disconnected state, TCP/IP stack 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 NULL pointer 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()得到一个非零,你处理数据;你得到零,你处理断开连接。

#2


4  

"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!

“如果你需要确定连接的当前状态,请进行非阻塞,零字节发送调用。如果调用成功返回或抛出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始终为true,即使已拔下以太网电缆,呼叫也始终成功返回。

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,好像是否已经发送了一些东西。虽然有问题的设备甚至不再连接。

#3


1  

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.
  • 套接字可以在顶部读取数据,在这种情况下,Receive将返回可读取的数据。
  • 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 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.

我个人从未使用过民意调查 - 我一直使用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连接的最有效和最好的方法。

#4


1  

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 he gets EOS and then closes the socket. So you have a guarantee that all the data has got into the peer application.

不,但如果您关闭套接字然后读取直到EOS,您正在等待对等方读取所有数据,直到他获得EOS然后关闭套接字。因此,您可以保证所有数据都已进入对等应用程序。