断开连接时,非阻塞recv返回0

时间:2013-07-24 03:47:21

标签: c++ c sockets

当发生断开连接时,我正试图“抓住”。 但实际上我没有弄到什么问题。 recv()返回0,errno设置为0,ioctl返回0.我在网上搜索了6个小时,但没有成功。谁能告诉我什么是错的?

问候。

bool Network::setBlocking(bool blocking)
{
    // sets blocking or non-blocking mode.

    int flags = blocking ? 1 : 0; 
    return ioctl(this->sockfd, FIONBIO, &flags) ? false : true;
}

NetworkStatus Network::status()
{
    // returns socket status.

    struct timeval tv;
    fd_set  fd;
    int result = 0;

    tv.tv_sec  = 3;
    tv.tv_usec = 0;

    FD_ZERO(&fd);
    FD_SET(this->sockfd, &fd);

    result = select(this->sockfd + 1, &fd, 0, 0, &tv);

    if(result == -1)
    {
        return NETWORK_ERROR;
    }
    else if(result)
    {
        return NETWORK_READYREAD;
    }
    else
    {
        return NETWORK_TIMEOUT;
    }
}

int Network::bytesAvailable()
{
    // returns number of bytes available.

    int bytes = 0;

    if(ioctl(this->sockfd, FIONREAD, &bytes) < 0 || errno)
    {
        return -1;
    }

    return bytes;
}

int Network::read(char *buffer, int size)
{
    // reads data from socket.

    return recv(this->sockfd, buffer, size, 0);
}
...
int main(int argc, char* argv[])
{
    Network net;
    ...
    while(true)
    {
        switch(net.status())
        {
            ...
            case NETWORK_READYREAD:
            {
                int bytesAvailable = net.bytesAvailable();
                char temp[bytesAvailable];
                int len = net.read(temp, bytesAvailable);
                printf("len: %d\nerrno: %d\nbytesAvailable: %d\n", len, errno, bytesAvailable); // len: 0, errno: 0, bytesAvailable: 0
                break;
            }
        }
    } // status
    return 0;
}

2 个答案:

答案 0 :(得分:7)

当对等体断开连接时,

recv()返回零。你没有问题。这是预期的,正确的行为。

答案 1 :(得分:5)

当另一侧关闭套接字或执行关闭(发送)时,在您旁边,select将返回套接字可读,因此select命令将返回1,表示有数据要读取(实际上没有数据,它只是一个指示套接字已关闭的信号),但ioctl返回0作为可用字节,recv()也返回0,那是TCP究竟如何工作。因此,在您的计划中,您应该注意bytesAvaliable返回0和/或read()返回0。在这些情况下,套接字已关闭,您也应该关闭您的一侧并等待(接受)或建立(连接)新连接。

编辑:添加内容:

嗯,不完全是。当recv() = 0,套接字关闭或关闭以进行发送时,= -1时套接字中存在错误。如果套接字是非阻塞的(已设置O_NONBLOCK),则应检查错误(在Windows上为errno,在Windows上为WSAGetLastError())和EWOULDBLOCK或{{1}表示没有可用数据且套接字仍然有效。此外,在极少数情况下,EAGAIN可能会返回recv(),错误-1也意味着在EINTR操作期间收到了中断(信号),你应该忽略错误(除非你正在等待这样的信号)并重新发出recv()

recv()

说明一点,你必须明确的一件事是,如果ret=recv(socket, buff, length, 0); if (ret > 0) { // data has been received } else if (ret == 0) { // socket has been closed or shutdown for send } else { // there is an error, let's see what it is int error = errno; // or WSAGetLastError() switch (error) { case EAGAIN: case EWOULDBLOCK: // Socket is O_NONBLOCK and there is no data available break; case EINTR: // an interrupt (signal) has been catched // should be ingore in most cases break; default: // socket has an error, no valid anymore return; } } 返回recv()0套接字不再有效且应该关闭,但是又取决于许多因素,用于在套接字之间保持对话的协议,如果它是非阻塞的等等。例如,另一方可以发出-1;在这种情况下,您的shutdown()将返回recv(),但您仍然可以通过该套接字执行0而不会出错。