如何检查客户端是不是通过 C++ 中的 Winsock 断开连接?

Posted

技术标签:

【中文标题】如何检查客户端是不是通过 C++ 中的 Winsock 断开连接?【英文标题】:How can I check if a client disconnected through Winsock in C++?如何检查客户端是否通过 C++ 中的 Winsock 断开连接? 【发布时间】:2009-03-26 14:07:56 【问题描述】:

如何在 C++ 中通过 Winsock 检查客户端是否断开连接?

【问题讨论】:

来自服务器,你想知道客户端套接字是否仍然连接? 定义“断开连接”;) 另一端的端口因任何原因而关闭。 参考我帖子中的链接,常见问题解答显示了大多数其他检查断开连接的方法。 【参考方案1】:

Beej's Network Programming Guide

如果你在阻塞模式下调用recv并返回读取0字节,则套接字已断开连接,否则它等待接收字节。

看看这个FAQ 2.12

this 页面上的选择示例。

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
    

【讨论】:

BSD 套接字,它们无处不在。【参考方案2】:

您只能通过尝试发送数据来判断 TCP 套接字是否“断开”。这是因为协议的设计使得它应该允许对等方之间的临时中断。因此,如果您从 A 通过 R1 通过 R2 通过 R3 连接到 B 并发送数据一段时间然后停止发送,您可以拔下 R2-> R3(例如)并且 A 和 B 都不会注意到(或关心)。如果您随后插入 R2->R4 和 R4->R3,然后尝试在 A 和 B 之间发送数据,那么事情将“正常工作”,而您永远不会知道。但是,如果您尝试在 R2->R3 断开连接时发送数据,那么您(最终,在所有 TCP 级别重试之后)会收到错误消息。

现在,某些操作系统可能会提醒您您的本地网络适配器当前未连接,您可以使用它来表示“我不再连接到我的同伴”,但我不会建议。

如果让您的对等方知道连接何时“断开”很重要,则可以使用应用程序级别的“ping”消息偶尔在对等方之间发送数据或使用 TCP 保持连接。就我个人而言,我会选择 ping 消息...

编辑:当然,所有这些都是假设您想知道您是否仍然可以在连接上发送数据,毕竟,当客户端不再发送时,您会被告知,因为您的读取将返回 0 个字节,并且您知道它何时断开其发送端,因为您的写入将失败;您还知道何时关闭您自己的连接端的发送或接收端...

我想我应该坚持“定义断开连接”的初始直觉反应;)

【讨论】:

【参考方案3】:

有几种不同的方法,但最常见的是检查发送或接收命令的结果:

 nReadBytes = recv(sd, ReadBuffer, BufferSize, 0);
 if (nReadBytes == SOCKET_ERROR)
 
     //error
 
 nSendBytes = send(sd, WriteBuffer, BufferSize, 0);
 if (nSendBytes == SOCKET_ERROR)
 
     //error
 

更多示例(完整的错误检查,包括客户端和服务器):

http://tangentsoft.net/wskfaq/examples/basics/

【讨论】:

【参考方案4】:

如果 send() 或 recv() 的结果是 SOCKET_ERROR 并且 WSAGetLastError() 返回 WSAECONNRESET 客户端已断开连接。 来自 MSDN:

WSAECONNRESET

对等方重置连接。

现有连接被远程主机强行关闭。这 通常如果远程主机上的对等应用程序是 突然停止,主机重启,主机或远程网络 接口被禁用,或远程主机使用硬关闭(请参阅 setsockopt 以获取有关远程 SO_LINGER 选项的更多信息 插座)。如果连接因以下原因而中断,也可能导致此错误 在一个或多个操作时检测故障的保持活动 正在进行中。正在进行的操作失败 WSAENETRESET。后续操作因 WSAECONNRESET 而失败。

这也适用于非阻塞套接字。

int r = recv(sock, NULL, 0, 0);
if(r == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET)
    //client has disconnected!

【讨论】:

以上是关于如何检查客户端是不是通过 C++ 中的 Winsock 断开连接?的主要内容,如果未能解决你的问题,请参考以下文章

如何检查字符串中的数据是不是是 C++ 上的数字?

如何检查数组中的所有值是不是彼此相等。 C++

如何检查向量的所有元素是不是在 Eigen c++ 中的另一个向量中?

如何使用 Qt (C++) 检查程序是不是按其名称运行

如何检查是不是在 Visual C++ 应用程序中的第三方 DLL 中创建了新线程

C++中的多线程,只检查信号量是不是被锁定