使用select()检测套接字断开连接的情况

7
我正在尝试使用select()函数检测客户端是否已经断开连接。问题是我不太理解select()如何工作。我正在使用以下代码,你能告诉我我做错了什么以及如何检测客户端是否已经断开连接吗? 我正在使用非阻塞套接字。
int Network::bytesAvailable()
{
    long bytes = 0;

    if(ioctl(this->sockfd, FIONREAD, &bytes) < 0)
    {
        printf("ERROR: Network:bytesAvailable: ioctl() call failed.\n");
        return -1;
    }

    return bytes;
}

NetworkStatus Network::status()
{
    struct timeval tv;
    fd_set  fd;
    int result = 0;

    tv.tv_sec  = 5;
    tv.tv_usec = 0;

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

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

    if(result && !this->bytesAvailable())
    {
        return -1; // disconnected, I'm guessing this is definitely WRONG.
    }
    else if(result > 0 && FD_ISSET(this->sockfd, &fd))
    {
        return 1; // bytes available.
    }
    else if(!result)
    {
        return 0; // timeout
    }

    return -1; // select() call failed.
}

通常我们使用 keepalive 来检测连接是否活动,并使用 select() 进行多路复用。这不正确吗? - Grijesh Chauhan
我不理解你的语法,请原谅 :) - user2399415
抱歉我的英语非常差 :( 但我编辑了评论,现在我被理解了吗? - Grijesh Chauhan
抱歉,不可以:) - user2399415
1个回答

11

当一个套接字关闭时,它变成“可读”,但调用recv会返回0字节。使用select函数,你可以知道何时可以从套接字读取数据,如果recv返回0,则表示套接字已关闭。

你的评论“可用字节数”并不完全准确。虽然可以从套接字中读取数据,但如果套接字已关闭,则没有可用的字节。

else if(result > 0 && FD_ISSET(this->sockfd, &fd))
{
    return 1; // bytes available.
}

在非阻塞套接字中,如果没有数据且套接字未关闭,则recv将返回-1并设置errnoEWOULDBLOCK(或EAGAIN)。


据我所知,在非阻塞套接字上,这是不正确的,因为recv可能会返回0(尚未接收到任何数据)。 - user2399415

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接