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

时间:2009-02-05 11:09:16

标签: .net sockets

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

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

  

如果需要确定电流   连接状态,制作一个   非阻塞,零字节发送呼叫。如果   调用成功返回或   抛出WAEWOULDBLOCK错误代码   (10035),然后套接字仍然是   连接的;否则,套接字是否定的   更长时间的连接。

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

Another post by Pete Duniho说:

  

...在你致电Shutdown()后,   致电Receive(),直到它返回0   (假设远程端点不是   实际上会送你什么,   这将在遥控器发生时立即发生   端点已收到你的全部   数据)。除非你那样做,否则你有   无法保证远程端点   实际上已收到所有数据   你发了,即使是挥之不去   插座。

我真的不理解他关于调用Receive()以确保远程端点实际收到我发送的所有数据的声明。 (套接字阻塞接收,直到发送缓冲区为空?)

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


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

4 个答案:

答案 0 :(得分:21)

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

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

  

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

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

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

调用Receive()可确保您接收来自远程端点的最后ACK数据包,或者发生断开连接超时,您将能够接收此插座上没有其他内容。

  

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

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

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

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


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

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

答案 1 :(得分:4)

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

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

bConnected始终为true,即使以太网电缆已拔下,呼叫也始终成功返回。

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

buffer[0] = 0xff ;
int iSent = mySocket.Send(buffer, 1, SocketFlags.None);

反复返回1,好像是否曾经发过一些东西。虽然有问题的设备甚至不再连接。

答案 2 :(得分:1)

通常会使用Socket.Select方法来确定一组套接字的状态(单个套接字的Socket.Poll)。

这两种方法都允许您查询套接字的状态。现在,假设您已经跟踪了首先连接的套接字,那么在尝试读取之前,通常会在套接字上调用Select / Poll。如果Select / Poll指示套接字是可读的,则会告诉您:

  • 套接字的数据可用顶部读取,在这种情况下,Receive将返回可读取的数据。
  • 套接字套接字已关闭,在这种情况下,当您调用Receive 0时,将立即返回字节(即,如果Select / Poll指示套接字是可读的,并且您调用Receive但它立即返回0字节,那么您知道连接已关闭,重置或已终止。

就我个人而言,我从未使用过民意调查 - 我一直使用Select,但MSDN似乎暗示Poll与Select非常相似,但单个套接字。

我还要补充一点,在大多数情况下,使用Select是处理套接字连接的最有效和最好的方法。

答案 3 :(得分:1)

  

我真的不理解他关于调用Receive()的声明,以确保远程端点实际上已收到我发送的所有数据。

@PeteDuniho的帖子并不是关于建立连接状态,而是以这样的方式终止连接,以便你知道对等体何时收到你的所有数据。

  

(套接字阻塞接收,直到发送缓冲区为空?)

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