如何检查客户端是否通过 C++ 中的 Winsock 断开连接?
4 回答
如果您在阻塞模式下调用 recv 并返回读取 0 字节,则套接字已断开连接,否则它等待接收字节。
查看此常见问题解答 2.12
此页面上的选择示例。
int nRet;
if(( nRet = select( 0, &fdread, NULL, NULL, NULL )) == SOCKET_ERROR )
{
// Error condition
// Check WSAGetLastError
}
if( nRet > 0 )
{
// select() will return value 1 because i m using only one socket
// At this point, it should be checked whether the
// socket is part of a set.
if( FD_ISSET( s, &fdread ))
{
// A read event has occurred on socket s
}
}
您只能通过尝试发送数据来判断 TCP 套接字是否“断开连接”。这是因为协议的设计使得它应该允许对等点之间的临时中断。因此,如果您从 A 通过 R1 通过 R2 通过 R3 连接到 B 并发送数据一段时间然后停止发送,您可以拔下 R2-> R3(例如)并且 A 和 B 都不会注意到(或关心)。如果您随后插入 R2->R4 和 R4->R3,然后尝试在 A 和 B 之间发送数据,那么事情将“正常工作”,而您永远不会知道。但是,如果您尝试在 R2->R3 断开连接时发送数据,那么您(最终,在所有 TCP 级别重试之后)会收到错误消息。
现在,某些操作系统可能会提醒您您的本地网络适配器当前未连接,您可以使用它来表示“我不再连接到我的对等设备”,但我不建议这样做。
如果让您的对等方知道连接何时“断开”很重要,那么要么使用应用程序级别的“ping”消息偶尔在对等方之间发送数据,要么使用 TCP 保持连接。就我个人而言,我会去 ping 消息...
编辑:当然,所有这些都假设您想知道您是否仍然可以在连接上发送数据,毕竟,当客户端不再发送时您会被告知,因为您的读取将返回 0 字节并且您知道它何时断开连接它的发送方,因为您的写入将失败;您还知道何时关闭您自己的连接端的发送或接收端......
我想我应该坚持“定义断开连接”的初始直觉反应;)
有几种不同的方法,但最常见的是检查发送或接收命令的结果:
nReadBytes = recv(sd, ReadBuffer, BufferSize, 0);
if (nReadBytes == SOCKET_ERROR)
{
//error
}
nSendBytes = send(sd, WriteBuffer, BufferSize, 0);
if (nSendBytes == SOCKET_ERROR)
{
//error
}
更多示例(包括客户端和服务器的错误检查):
如果 send() 或 recv() 的结果是 SOCKET_ERROR 并且 WSAGetLastError() 返回 WSAECONNRESET 客户端已断开连接。
来自 MSDN:
WSAECONNRESET
对等方重置连接。
现有连接被远程主机强行关闭。如果远程主机上的对等应用程序突然停止,主机重新启动,主机或远程网络接口被禁用,或者远程主机使用硬关闭,这通常会导致(有关远程主机上 SO_LINGER 选项的更多信息,请参阅 setsockopt插座)。如果在一个或多个操作正在进行时,由于保活活动检测到故障而导致连接中断,则也可能导致此错误。正在进行的操作因 WSAENETRESET 而失败。后续操作因 WSAECONNRESET 而失败。
这也适用于非阻塞套接字。
int r = recv(sock, NULL, 0, 0);
if(r == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET){
//client has disconnected!
}