How do I change a TCP socket to be non-blocking?

You're misinformed about fcntl() not always being reliable. It's untrue.

To mark a socket as non-blocking the code is as simple as:

// where socketfd is the socket you want to make non-blocking
int status = fcntl(socketfd, F_SETFL, fcntl(socketfd, F_GETFL, 0) | O_NONBLOCK);

if (status == -1){
  perror("calling fcntl");
  // handle the error.  By the way, I've never seen fcntl fail in this way
}

Under Linux, on kernels > 2.6.27 you can also create sockets non-blocking from the outset using socket() and accept4().

e.g.

   // client side
   int socketfd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);

   // server side - see man page for accept4 under linux 
   int socketfd = accept4( ... , SOCK_NONBLOCK);

It saves a little bit of work, but is less portable so I tend to set it with fcntl().


What do you mean by "not always reliable"? If the system succeeds in setting your socket non non-blocking, it will be non-blocking. Socket operations will return EWOULDBLOCK if they would block need to block (e.g. if the output buffer is full and you're calling send/write too often).

This forum thread has a few good points when working with non-blocking calls.


fcntl() has always worked reliably for me. In any case, here is the function I use to enable/disable blocking on a socket:

#include <fcntl.h>

/** Returns true on success, or false if there was an error */
bool SetSocketBlockingEnabled(int fd, bool blocking)
{
   if (fd < 0) return false;

#ifdef _WIN32
   unsigned long mode = blocking ? 0 : 1;
   return (ioctlsocket(fd, FIONBIO, &mode) == 0) ? true : false;
#else
   int flags = fcntl(fd, F_GETFL, 0);
   if (flags == -1) return false;
   flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
   return (fcntl(fd, F_SETFL, flags) == 0) ? true : false;
#endif
}

Tags:

C

Sockets