recv()返回零但无法看到任何TCP断开连接

时间:2016-07-14 17:00:20

标签: c linux sockets tcp glibc

我使用以下代码在套接字上接收。 recv()返回零字节,意味着连接已断开连接,除非它看起来不像:

while( true )
{                  
    buffer = onGetBuffer( maxBytesToRecv );

    const int flags = MSG_WAITALL;

    errno = 0;
    const ssize_t bytesReceived = ::recv( descriptor() , buffer , maxBytesToRecv , flags );

    if ( bytesReceived > 0 ){
        processData( receivedTime , bytesReceived );   
    }
    else if ( bytesReceived < 0 ){
        const int eno = errno;
        if ( EINTR != eno ){
            // Log error code
        }
    }
    else{
        // Peer disconnected
        // ** Code is reaching here **
    }                   
}

我正在点击暗示对等点已断开的分支,因为bytesReceived为零。我检查了一个pcap转储,但我们没有收到TCP FIN消息来关闭连接。

我在此过程中运行了strace(过滤网络消息)以检查我们是否自己关闭了连接并且对于所记录的插槽:

sendto(16, "DATA"..., 88, MSG_NOSIGNAL, NULL, 0) = 88
sendto(16, "DATA"..., 88, MSG_NOSIGNAL, NULL, 0) = 88
sendto(16, "DATA"..., 5584, MSG_NOSIGNAL, NULL, 0) = 5584
sendto(16, "DATA"..., 5654, MSG_NOSIGNAL, NULL, 0) = 5654
sendto(16, "DATA"..., 5651, MSG_NOSIGNAL, NULL, 0) = 5651
sendto(16, "DATA"..., 5593, MSG_NOSIGNAL, NULL, 0) = 5593
sendto(16, "DATA"..., 5635, MSG_NOSIGNAL, NULL, 0) = 5635
sendto(16, "DATA"..., 5563, MSG_NOSIGNAL, NULL, 0) = 5563
sendto(16, "DATA"..., 5608, MSG_NOSIGNAL, NULL, 0) = 5608
sendto(16, "DATA"..., 5662, MSG_NOSIGNAL, NULL, 0 <unfinished ...>
sendto(16, "DATA"..., 5583, MSG_NOSIGNAL, NULL, 0) = 5583
sendto(16, "DATA"..., 5579, MSG_NOSIGNAL, NULL, 0) = 5579
sendto(16, "DATA"..., 3373, MSG_NOSIGNAL, NULL, 0) = 3373
sendto(16, "DATA"..., 201, MSG_NOSIGNAL, NULL, 0) = 201
recvfrom(16, "DATA"..., 7126, MSG_WAITALL, NULL, NULL) = 7126
recvfrom(16, "DATA"..., 6187, MSG_WAITALL, NULL, NULL) = 6187
recvfrom(16, "DATA"..., 7079, MSG_WAITALL, NULL, NULL) = 7079
recvfrom(16, "", 0, MSG_WAITALL, NULL, NULL) = 0

其中16是套接字的描述符。最后,您可以看到最终的收到返回0。

如果我们没有断开连接,我们没有从另一方收到TCP FIN来断开我们的连接。没有返回错误代码,errno也为零。

如果没有断开连接,为什么recv()会返回零?或者我还能检查什么?

2 个答案:

答案 0 :(得分:4)

您的最终recv来电是0字节。

来自Linux上的recv手册页:

  

如果从流套接字接收的请求字节数为0,则也可以返回值0。

作为对该计划的评论,我认为maxBytesToRecv是一种奇怪的全球或阶级成员。如果程序信任数据流来声明这些块的大小,它看起来也可能是一个巨大的安全漏洞。

信任,但验证。边界检查长度值。处理零尺寸以解决此问题,但也检查太大的尺寸。由于巨大的值和整数溢出,已经发生了许多很多漏洞。或者更糟糕的是,将无符号长度复制到有符号整数中,并将0xFFFF视为65535某些地方和-1其他地方。

答案 1 :(得分:0)

最后一次调用 recv() 是否要求长度为零?

recvfrom(16, "", 0, MSG_WAITALL, NULL, NULL) = 0

如果您询问零字节,则您收到零字节。