Background: I understand I can't just call accept()
straight away after select()
and assume it will work because there is a chance the client might have disconnected after select()
returned, even if select()
tells me the socket is ready for accept()
. Rather, I need to set the socket to O_NONBLOCK
and then test for EAGAIN/EWOULDBLOCK
when I call accept()
- see below.
Question: Do I need to do that same thing with select()
/recv()
? If select()
tells me a socket is ready to read, can I call recv()
and guarantee it will not block (or report EAGAIN/EWOULDBLOCK
if it's a non-blocking socket)?
Here is the code I'm using for the accept()
case:
while(true) {
fd_ready = select_for_read(listen_fds, 2);
fd_client = accept(fd_ready, (struct sockaddr *)&client_addr, &client_addr_len);
if (fd_client == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
continue;
} else {
exit_with_error("Error accepting connection from client");
}
}
break;
}
(select_for_read
takes an array of file descriptors and blocks until one is ready to read using select()
.)
From the select man page for Linux:
Under Linux, select() may report a socket file descriptor as "ready for reading", while nevertheless a subsequent read blocks. This could for example happen when data has arrived but upon examination
has wrong checksum and is discarded. There may be other circumstances in which a file descriptor is spuriously reported as ready. Thus it may be safer to use O_NONBLOCK on sockets that should not block.
Of course, that warning is in the bugs section, implying that the authors think that isn't an expected behavior -- but nevertheless, under Linux at least it is something that can happen. Personally, I always set my sockets to be non-blocking; that way I don't have to worry about my program accidentally blocking anywhere other than where I intended it to block (i.e. inside select()).