简体   繁体   English

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

[英]Is "reading zero bytes" from a socket a valid way for monitoring a TCP/IP disconnect in POSIX C?

I'm currently reviewing a C application that implements POSIX sockets.我目前正在审查实现 POSIX sockets 的 C 应用程序。 This application intermittently checks to see if the connection to the server is valid by reading zero bytes from the socket.此应用程序通过从套接字读取零字节来间歇性地检查与服务器的连接是否有效。 It then checks to see if an errno is set to determine whether or not the connection is okay.然后它检查是否设置了 errno 以确定连接是否正常。 Is this a robust solution?这是一个强大的解决方案吗?

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;
}

No, this is not a robust solution, for two reasons.不,这不是一个可靠的解决方案,原因有两个。

First, for a connected TCP socket read and recv will return zero, not −1, after all incoming data has been read and the remote peer has closed its end of the connection (using close or shutdown ).首先,对于已连接的 TCP 套接字,在读取所有传入数据并且远程对等方已关闭其连接端(使用closeshutdown )后, readrecv将返回零,而不是 -1。 Your IsConnected will return TRUE in this case, which is wrong.在这种情况下,您的IsConnected将返回 TRUE,这是错误的。

Second, the specification of read says (second paragraph of DESCRIPTION; all emphasis mine)第二, read的规范说(描述的第二段;所有强调我的)

Before any action described below is taken, and if nbyte is zero, the read function may detect and return errors as described below.在采取下述任何操作之前,如果nbyte为零,则read function可能会检测并返回如下所述的错误。 In the absence of errors, or if error detection is not performed , the read function shall return zero and have no other results.在没有错误的情况下,或者如果没有执行错误检测read function 将返回零并且没有其他结果。

nbyte is the third argument, which your IsConnected is supplying as zero. nbyte是第三个参数,您的IsConnected提供为零。 Therefore, depending on the operating system, IsConnected might always return TRUE, regardless of the state of the socket.因此,取决于操作系统, IsConnected可能总是返回 TRUE,而不管套接字的 state。

The specification of recv does not say anything about what happens if the length argument (equivalent to nbyte for read ) is zero;如果length参数(相当于readnbyte )为零recv的规范没有说明会发生什么。 I think this is probably an oversight and it (and recvfrom , recvmsg , etc.) is meant to have the same special behavior as read .我认为这可能是一个疏忽,它(和recvfromrecvmsg等)旨在具有与read相同的特殊行为。 So changing read to recv will not fix the problem by itself.因此,将read更改为recv本身并不能解决问题。 However, I think a complete fix is possible by using recv with MSG_PEEK :但是,我认为通过使用带有MSG_PEEKrecv可以实现完整的修复:

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;
}

Using MSG_PEEK allows you to supply a nonzero length, because the data will not actually be consumed.使用MSG_PEEK允许您提供非零长度,因为实际上不会使用数据。

Depending on the details of the application and its network protocol, you may also want to consider enabling TCP keep-alive packets on the socket.根据应用程序及其网络协议的详细信息,您可能还需要考虑在套接字上启用 TCP 保持活动数据包

Yes.是的。 This is explained in man 2 recv , Return value section:这在man 2 recv返回值部分中进行了解释:

These calls return the number of bytes received, or -1 if an error occurred.这些调用返回接收到的字节数,如果发生错误,则返回 -1。 In the event of an error, errno is set to indicate the error.如果发生错误,则设置 errno 以指示错误。

When a stream socket peer has performed an orderly shutdown, the return value will be 0 (the traditional "end-of-file" return).当 stream 套接字对等体执行了有序关闭时,返回值为 0(传统的“文件结束”返回)。

Datagram sockets in various domains (eg, the UNIX and Internet domains) permit zero-length datagrams.各种域(例如,UNIX 和 Internet 域)中的数据报 sockets 允许零长度数据报。 When such a datagram is received, the return value is 0.当接收到这样的数据报时,返回值为 0。

The value 0 may also be returned if the requested number of bytes to receive from a stream socket was 0.如果从 stream 套接字接收的请求字节数为 0,则也可能返回值 0。

A TCP socket is a stream socket, so as long as you make sure your recv() / read() call uses a buffer with nonzero size, a zero return indicates the peer has performed an orderly shutdown.一个 TCP 套接字是一个 stream 套接字,所以只要你确保你的recv() / read()调用使用非零大小的缓冲区,零返回表示对等方已执行有序关闭。

An orderly shutdown is one of two things: closing the socket, or calling shutdown() on it (in this case, with either SHUT_WR or SHUT_RDWR, former indicating it will not send any further data but is able to receive, and the latter indicating it will not send or receive any data).有序关闭是以下两种情况之一:关闭套接字,或在其上调用shutdown() (在这种情况下,使用 SHUT_WR 或 SHUT_RDWR,前者表示它不会发送任何进一步的数据但能够接收,后者表示它不会发送或接收任何数据)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM