leohotfn
leohotfn

Reputation: 11

Why is a newly created socket readble and writable, which is monitored by select()?

I wrote the following code. I create a socket , and use select() to monitor this newly created socket. After select() calling, this socket is detected readable and writable.

How to explain this phenomenon? Does it have anything to do with socket recvbuf/sndbuf and 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;
}

Output:

socket is readable
socket is writable

Upvotes: 1

Views: 99

Answers (1)

John Bollinger
John Bollinger

Reputation: 180161

To begin with, Linux / glibc's select() is documented to sometimes spuriously report file descriptors to be readable, but we don't need to rely on that to explain the behavior.

The main issue appears to be that you misinterpret the meaning of select() setting a file descriptor in one of the provided read or write fd sets. That does not necessarily mean that data can successfully be transferred via the fd. Rather it means that the fd entered or was already in a state where an attempt to do so would not block, which includes the case that such an attempt would fail without blocking. The Linux and especially the POSIX documentation is clear on this point.

With that being the case, the behavior you describe is exactly what I would expect. You've created a stream-oriented socket but not connected it to a peer, so I would expect read() and write() attempts on it to fail immediately. select() is therefore right to return its file descriptor in its read and write fd sets.

Upvotes: 2

Related Questions