我应该如何检查(TCP)套接字以确定它是否已连接?
我已经阅读了MSDN中的Socket.Connected
属性,但它说它只显示了根据最后一个I / O的状态。这对我没用,因为我想在尝试从套接字读取之前执行此操作。备注部分还指出:
如果需要确定电流 连接状态,制作一个 非阻塞,零字节发送呼叫。如果 调用成功返回或 抛出WAEWOULDBLOCK错误代码 (10035),然后套接字仍然是 连接的;否则,套接字是否定的 更长时间的连接。
同一页面上的示例显示了如何执行此操作。(1)但a post by Ian Griffiths表示我应该从套接字读取,而不是通过它发送。
...在你致电
Shutdown()
后, 致电Receive()
,直到它返回0
(假设远程端点不是 实际上会送你什么, 这将在遥控器发生时立即发生 端点已收到你的全部 数据)。除非你那样做,否则你有 无法保证远程端点 实际上已收到所有数据 你发了,即使是挥之不去 插座。
我真的不理解他关于调用Receive()
以确保远程端点实际收到我发送的所有数据的声明。 (套接字阻塞接收,直到发送缓冲区为空?)
我对提出的不同方法感到困惑。你能解释一下吗?
(1)我想知道为什么Socket.Connected
属性的example分配一个1字节的数组,即使它调用Send
的长度为0?
答案 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指示套接字是可读的,则会告诉您:
就我个人而言,我从未使用过民意调查 - 我一直使用Select,但MSDN似乎暗示Poll与Select非常相似,但单个套接字。
我还要补充一点,在大多数情况下,使用Select是处理套接字连接的最有效和最好的方法。
答案 3 :(得分:1)
我真的不理解他关于调用Receive()的声明,以确保远程端点实际上已收到我发送的所有数据。
@PeteDuniho的帖子并不是关于建立连接状态,而是以这样的方式终止连接,以便你知道对等体何时收到你的所有数据。
(套接字阻塞接收,直到发送缓冲区为空?)
不,但是如果您关闭套接字然后读取直到EOS,那么您正在等待对等方读取所有数据,直到他获得EOS然后关闭套接字。因此,您可以保证所有数据都已进入对等应用程序。