The Linux man pages describes the select()
function https://man7.org/linux/man-pages/man2/select.2.html in this way:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
select() allows a program to monitor multiple file descriptors,
waiting until one or more of the file descriptors become "ready" for
some class of I/O operation (e.g., input possible). A file
descriptor is considered ready if it is possible to perform a
corresponding I/O operation (e.g., read(2), or a sufficiently small
write(2)) without blocking.
The goal of select()
is to allow you to test whether one or more sockets are ready for an action or not. The timeout
parameter allows you to specify how long to wait for any of the sockets to be ready. So this is a synchronous call in that you call the function and it will either return when one or more of the sockets are ready for an action or, if a time out value was specified, when the time out has expired.
On success, select() and pselect() return the number of file
descriptors contained in the three returned descriptor sets (that is,
the total number of bits that are set in readfds, writefds,
exceptfds). The return value may be zero if the timeout expired
before any file descriptors became ready.
On error, -1 is returned, and errno is set to indicate the error; the
file descriptor sets are unmodified, and timeout becomes undefined.
You specify which sockets are to be checked by the select()
by specifying a map using the FD_SET()
macro. See Socket programming in C, using the select() function as well as Polling using Select function in C++ on Windows and Is it necessary to reset the fd_set between select system call? for examples.
If you have more than one socket set in a mask or are using multiple masks with sockets set then when the select()
function returns indicating that one or more sockets are ready, you need to use the FD_ISSET()
macro to determine which of the sockets you have requested a status on are actually ready.
However if you have specified only a single socket in only one of the masks then when the select()
returns indicating a sockets is ready, you only have one socket that could be ready.
The reason for using the FD_ISSET()
anyway is just as a check no matter what. Think of it as good programming practice as well as improving robustness of the source code in the face of maintenance which may add other sockets in the future.
If you call accept()
with a blocking listening socket and there is not a connection waiting to be accepted then the thread is going to block on the accept()
until a connection request is received. https://man7.org/linux/man-pages/man2/accept.2.html
If no pending connections are present on the queue, and the socket is
not marked as nonblocking, accept() blocks the caller until a
connection is present. If the socket is marked nonblocking and no
pending connections are present on the queue, accept() fails with the
error EAGAIN or EWOULDBLOCK.
In order to be notified of incoming connections on a socket, you can
use select(2), poll(2), or epoll(7). A readable event will be
delivered when a new connection is attempted and you may then call
accept() to get a socket for that connection. Alternatively, you can
set the socket to deliver SIGIO when activity occurs on a socket; see
socket(7) for details.
Since you are using select()
to check if the listening socket is ready the most probably having accept()
block is not the behavior you desire so using FD_ISSET()
first before calling accept()
seems the most prudent course of action.