从套接字“读取零字节”是否是监视 POSIX C 中 TCP/IP 断开连接的有效方法?

Izz*_*zzo 1 c sockets linux posix tcp

我目前正在审查一个实现 POSIX 套接字的 C 应用程序。此应用程序通过从套接字读取零字节来间歇性地检查与服务器的连接是否有效。然后检查是否设置了 errno 以确定连接是否正常。这是一个强大的解决方案吗?

uint32_t IsConnected()
{
        char dummy[10];
        if(read(global_sockfd, dummy, 0) == -1)
        {
            if(errno != EWOULDBLOCK && errno != EAGAIN)
                return FALSE;
            else
                return TRUE;
        }   
        else
            return TRUE;
}
Run Code Online (Sandbox Code Playgroud)

zwo*_*wol 6

不,这不是一个强大的解决方案,原因有两个。

首先,对于已连接的 TCP 套接字,在读取所有传入数据并且远程对等方已关闭其连接端(使用或)后readrecv将返回零,而不是 ?1 。在这种情况下,您将返回 TRUE,这是错误的。closeshutdownIsConnected

二、说明的read说明(说明的第二段;全部强调我的)

在采取下面描述的任何操作之前,如果nbyte为零,该read函数可能会检测并返回如下所述的错误。如果没有错误,或者没有执行错误检测read函数将返回零并且没有其他结果。

nbyte是第三个参数,您IsConnected将其作为零提供。因此,根据操作系统的不同,无论套接字的状态如何,都IsConnected可能始终返回 TRUE。

规范recv没有说明如果length参数(相当于nbytefor read)为零时会发生什么;我想这可能是一个监督和它(和recvfromrecvmsg等等)是指具有相同的特殊行为read。因此,更改readrecv本身并不能解决问题。但是,我认为使用recvwith可以完全修复MSG_PEEK

bool is_connected(int sock)
{
    char dummy[1];
    ssize_t nread = recv(sock, dummy, sizeof dummy, MSG_PEEK);
    if (nread > 0)
        return true;    // at least one byte of data available
    else if (nread == 0)
        return false;   // EOF
    else
        return errno == EWOULDBLOCK || errno == EAGAIN;
}
Run Code Online (Sandbox Code Playgroud)

UsingMSG_PEEK允许您提供非零长度,因为实际上不会消耗数据。

根据应用程序及其网络协议的详细信息,您可能还需要考虑在套接字上启用 TCP 保持活动数据包