This is rather theoretical question. If sockets I/O (either read or write) is set to O_NONBLOCK, but then this socket is set in fd_set to select() which blocks (waiting for an event the file descriptor become either readable or writable), then that socket is blocking anyway (due to the select())?
Why would I set the socket to be non-blocking, when even the blocking (default) version once become readable (or writable) (thanks to select()), won't block, because the select() said it has data to read (or write) and thus the socket is able to perform its operation with that data without blocking. So why to bother setting socket non-blocking when select() blocks anyway?
An example of having non-block sockets, but in conjuction with blocking select():
#include <unp.h>
void str_cli(FILE *fp, int sockfd)
{
int flags, maxfd, stdineof;
fd_set rset, wset;
ssize_t nbytes, nactual;
//struct bufpos { char *read_ptr, *write_ptr; };
struct bufpos ipos, opos;
char inbuf[BSIZE], outbuf[BSIZE];
//--//
//set nonblocking flag for these fds:
int nblkFds[3] = {sockfd, STDIN_FILENO, STDOUT_FILENO};
for (int i = 0; i < 3; i++)
{
flags = Fcntl(nblkFds[i], F_GETFL, 0);
Fcntl(nblkFds[i], F_SETFL, flags | O_NONBLOCK);
}
//initialize buffer positions
ipos.write_ptr = ipos.read_ptr = inbuf;
opos.write_ptr = opos.read_ptr = outbuf;
stdineof = 0; //stdin
maxfd = max(STDOUT_FILENO, sockfd) + 1;
while (1)
{
FD_ZERO(&rset);
FD_ZERO(&wset);
//can read from stdin and readptr is not at the end of buffer
if (stdineof == 0 && opos.read_ptr < &outbuf[BSIZE])
{
FD_SET(STDIN_FILENO, &rset);
}
//can read from socket and the readptr is not at then end of buffer
if (ipos.read_ptr < &inbuf[BSIZE])
{
FD_SET(sockfd, &rset);
}
//difference in outbuf == data to write to socket
if (opos.read_ptr != opos.write_ptr)
{
FD_SET(sockfd, &wset);
}
//difference in inbuf == data to write to file
if (ipos.read_ptr != ipos.write_ptr)
{
FD_SET(STDOUT_FILENO, &wset);
}
Select(maxfd, &rset, &wset, NULL, NULL);
if (FD_ISSET(STDIN_FILENO, &rset))
{
switch ((nbytes = read(STDIN_FILENO, opos.read_ptr, &outbuf[BSIZE] - opos.read_ptr)))
{
case -1:
perror("read");
if (errno != EWOULDBLOCK)
{
die("read");
}
case 0:
fprintf(stderr, "%s: EOF on stdin\n", nowtime());
stdineof = 1;
if (opos.write_ptr == opos.read_ptr)
{
//everything was written to socket -> we won't be writing enything else -> close the connection by sending FIN
Shutdown(sockfd, SHUT_WR);
}
break;
default:
fprintf(stderr, "%s: read %ld bytes from stdin\n", nowtime(), nbytes);
//move the read pointer with bytes writen
opos.read_ptr += nbytes;
//now those bytes could be writen to socket
FD_SET(sockfd, &wset);
}
}
if (FD_ISSET(sockfd, &rset))
{
switch ((nbytes = read(sockfd, ipos.read_ptr, &inbuf[BSIZE] - ipos.read_ptr)))
{
case -1:
perror("read");
if (errno != EWOULDBLOCK)
{
die("read");
}
case 0:
fprintf(stderr, "%s: EOF on socket\n", nowtime());
if (stdineof)
{
//normal termination (client EOF)
return;
}
else
{
//RST from peer
die("str_cli: server terminated prematurely");
}
break;
default:
fprintf(stderr, "%s: read %ld bytes from socket\n", nowtime(), nbytes);
//move the read pointer with bytes read
ipos.read_ptr += nbytes;
//those bytes could be writen to file
FD_SET(STDOUT_FILENO, &wset);
}
}
if (FD_ISSET(STDOUT_FILENO, &wset) && (nbytes = ipos.read_ptr - ipos.write_ptr) > 0)
{
//the stdout is writeable and there are some bytes to write
switch ((nactual = write(STDOUT_FILENO, ipos.write_ptr, nbytes)))
{
case -1:
perror("write");
if (errno != EWOULDBLOCK)
{
die("write");
}
default:
fprintf(stderr, "%s: wrote %ld bytes to stdout\n", nowtime(), nactual);
ipos.write_ptr += nactual;
if (ipos.write_ptr == ipos.read_ptr)
{
//back to beginning buffer if all was writen to stdout
ipos.write_ptr = ipos.read_ptr = inbuf;
}
}
}
if (FD_ISSET(sockfd, &wset) && ((nbytes = opos.read_ptr - opos.write_ptr) > 0))
{
//the socket is writeable and there are some bytes to write
switch ((nactual = write(sockfd, opos.write_ptr, nbytes)))
{
case -1:
perror("write");
if (errno != EWOULDBLOCK)
{
die("write");
}
default:
fprintf(stderr, "%s wrote %ld bytes to socket\n", nowtime(), nactual);
opos.write_ptr += nactual;
if (opos.write_ptr == opos.read_ptr)
{
//back to beginning buffer if all was send/writen to socket
opos.read_ptr = opos.write_ptr = outbuf;
if (stdineof)
{
//EOF, could send its FIN
Shutdown(sockfd, SHUT_WR);
}
}
}
}
}
}
selectignoresO_NONBLOCKbut it does not change the fact that the socket is in fact still a non blocking one. why to bother setting socket non-blocking when select() blocks anyway. Why indeed. Have you seen code that does that? There probably are such uses cases but it's probably also not the common case. - kaylum