为什么新创建的套接字是可读写的,并由select()监视?

时间:2019-06-14 14:43:16

标签: c++ linux sockets

我编写了以下代码。我创建一个套接字,并使用select()监视此新创建的套接字。在select()调用之后,此套接字被检测为可读写。

如何解释这种现象?与套接字recvbuf / sndbuf和recvlowat / sndlowat有关系吗?

#include <iostream>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>


int main()
{
    int nClientFd = socket(AF_INET, SOCK_STREAM, 0);
    if (nClientFd == -1)
    {
        std::cout << "create socket failed, errno: " << errno << std::endl;
        return -1;
    }

    fd_set readFdSet;
    FD_ZERO(&readFdSet);
    FD_SET(nClientFd, &readFdSet);

    fd_set writeFdSet;
    FD_ZERO(&writeFdSet);
    FD_SET(nClientFd, &writeFdSet);

    struct timeval stTimeout;
    stTimeout.tv_sec = 1;
    stTimeout.tv_usec = 0;

    if (select(nClientFd + 1, &readFdSet, &writeFdSet, nullptr, &stTimeout) == -1)
    {
        std::cout << "select failed" << std::endl;
        close(nClientFd);
        return -1;
    }

    if (FD_ISSET(nClientFd, &readFdSet))
    {
        std::cout << "socket is readable" << std::endl;
    }

    if (FD_ISSET(nClientFd, &writeFdSet))
    {
        std::cout << "socket is writable" << std::endl;
    }

    close(nClientFd);
    return 0;
}

输出:

socket is readable
socket is writable

1 个答案:

答案 0 :(得分:2)

首先,Linux / glibc的select()被记录为有时会虚假地报告文件描述符以使其可读,但是我们不需要依靠它来解释行为。

主要问题似乎是您误解了select()在提供的读取或写入fd集之一中设置文件描述符的含义。这并不一定意味着可以通过fd成功传输数据。相反,这意味着fd进入或已经处于尝试不会被阻止的状态,包括这样的尝试将在没有阻止的情况下失败的情况。 Linux,尤其是POSIX文档在这一点上很清楚。

在这种情况下,您描述的行为正是我所期望的。您已经创建了面向流的套接字,但未将其连接到对等方,因此我期望read()write()对其进行的尝试立即失败。因此,select()有权在其读写fd集中返回其文件描述符。