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

Hos*_*Aly 34 .net sockets

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

我已经阅读了MSDN中Socket.Connected属性,但它说它只根据最后一个I/O显示状态.这对我没用,因为我想尝试从套接字读取之前这样做.备注部分还指出:

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

同一页面上的示例显示了如何执行此操作.(1)Ian Griffiths的帖子说我应该从套接字读取,而不是通过它发送.

Pete Duniho的另一篇文章说:

...在你打电话之后Shutdown(),打电话Receive()直到它返回0 (假设远程端点实际上不会向你发送任何东西,一旦远程端点收到你的所有数据就会发生这种情况).除非您这样做,否则您无法保证远程端点实际上已收到您发送的所有数据,即使使用延迟套接字也是如此.

我真的不明白他关于调用Receive()以确保远程端点实际上已经收到我发送的所有数据的说法.(套接字阻塞接收,直到发送缓冲区为空?)

我对提出的不同方法感到困惑.你能解释一下吗?


(1)但不知为何,例如Socket.Connected属性分配1字节的数组,即使它调用Send与0长度?

Qua*_*noi 22

套接字死亡会以多种方式改变其行为,因此这些方法都是有效的:)

使用这两种方法,您实际上会检查在断开连接后更改的套接字行为的那些部分.

我真的不明白他关于调用Receive()以确保远程端点实际上已经收到我发送的所有数据的说法.(套接字阻塞接收,直到发送缓冲区为空?)

TCP是可靠的协议,这意味着您发送的每个数据包都必须得到确认.确认意味着发送具有ACK位集的数据包.这些数据包可能包含也可能不包含其他(有效负载)数据.

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

调用Receive()可确保您从远程端点接收最后一个ACK数据包或发生断开连接超时,并且您将无法在此套接字上接收更多信息.

同一页面上的示例显示了如何执行此操作.(我想知道为什么它会分配一个1字节的数组,即使它调用的是0长度的发送?)但Ian Griffiths的一篇文章说我应该从套接字读取,而不是通过它发送.

send()进入套接字时,实际上会尝试将一些数据附加到套接字队列的末尾.缓冲区中是否还有一些地方Send(),如果没有,则会立即返回,Send()直到有一些地方为止.

当套接字处于断开状态时,TCP/IP堆栈会阻止缓冲区的所有进一步操作,这就是Send()返回错误的原因.

Send()实现基本指针检查,这意味着当NULL指针传递给它时它会失败.您可能会将任何非空常量作为指针传递,但您最好分配1个字节而不是使常量增加 - 以防万一.


您可以使用任何您喜欢的方法,因为它们都不占用资源.只要它们用于套接字连接检查,它们就是相同的.

至于我,我更喜欢Receive(),因为这是你通常在一个周期中运行并等待的东西.你得到一个非零Receive(),你处理数据; 你得到零,你处理断开连接.


小智 6

"如果需要确定连接的当前状态,请进行非阻塞、零字节的 Send 调用。如果调用成功返回或抛出 WAEWOULDBLOCK 错误代码 (10035),则表示套接字仍处于连接状态;否则,套接字处于连接状态不再连接。” ——不幸的是,它甚至不起作用!

mySocket.Blocking = false;
byte[] buffer = new byte[1];
int iSent = mySocket.Send(buffer, 0, SocketFlags.None);
bConnected = mySocket.Connected;
Run Code Online (Sandbox Code Playgroud)

bConnected 总是以真结束,并且呼叫总是成功返回,即使以太网电缆已被拔出。

此外,不幸的是 == 发送任何实际数据也不会检测到断开的连接。

buffer[0] = 0xff ;
int iSent = mySocket.Send(buffer, 1, SocketFlags.None);
Run Code Online (Sandbox Code Playgroud)

重复返回 1,就好像真的发送了什么一样。虽然有问题的设备甚至不再连接。

  • 我从(不太出色的)MSDN 示例中假设,您必须处理异常并在出现异常时手动返回 false。即 Socket.Connected 值在异常后可能具有无效值。如果您手动处理异常,则无法从您的代码片段中判断出来。 (2认同)