我应该如何检查(TCP)套接字以确定它是否已连接?
我已经阅读了MSDN中的Socket.Connected属性,但它说它只根据最后一个I/O显示状态.这对我没用,因为我想在尝试从套接字读取之前这样做.备注部分还指出:
如果需要确定连接的当前状态,请进行非阻塞,零字节发送调用.如果调用成功返回或抛出WAEWOULDBLOCK错误代码(10035),则套接字仍然连接; 否则,套接字不再连接.
同一页面上的示例显示了如何执行此操作.(1)但Ian Griffiths的帖子说我应该从套接字读取,而不是通过它发送.
...在你打电话之后
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,就好像真的发送了什么一样。虽然有问题的设备甚至不再连接。