A couple of days ago I had to investigate a problem where my application was showing abnormally high CPU usage when it was (apparently) in idle state. I tracked the problem down to a loop which was meant to block on a recvfrom
call while the socket had been set to O_NONBLOCK
-ing resulting in a spin lock. There were two ways of solving the problem: set the socket to blocking or poll for available data on the socket using poll
or select
. I chose the former as it was simpler. But I am wondering why any one would create a non-blocking socket and then poll on it separately. Doesn't a blocking socket do the same? What are the uses cases where one would use a non-blocking socket and poll combination? Are there any advantages to it in general cases?
The poll() API allows simultaneous connection with all descriptors in the queue on the listening socket. The accept() and recv() APIs are completed when the EWOULDBLOCK is returned. The send() API echoes the data back to the client. The close() API closes any open socket descriptors.
To mark a socket as non-blocking, we use the fcntl system call. Here's an example: int flags = guard(fcntl(socket_fd, F_GETFL), "could not get file flags"); guard(fcntl(socket_fd, F_SETFL, flags | O_NONBLOCK), "could not set file flags"); Here's a complete example.
From MSDN, the return value of connect(): On a blocking socket, the return value indicates success or failure of the connection attempt. With a nonblocking socket, the connection attempt cannot be completed immediately. In this case, connect will return SOCKET_ERROR , and WSAGetLastError() will return WSAEWOULDBLOCK.
The select() call has you create three bitmasks to mark which sockets and file descriptors you want to watch for reading, writing, and errors, and then the operating system marks which ones in fact have had some kind of activity; poll() has you create a list of descriptor IDs, and the operating system marks each of ...
Using poll()
or select()
with a non-blocking file descriptor gives you two advantages:
If you only have a single file descriptor (socket) to wait for, and you don't mind waiting indefinitely on it, then yes; you can just use a blocking call.
The second advantage is really the killer use case for select()
and friends. It means that you can handle multiple socket connections, as well as standard input and standard output and possibly file I/O, all with a single thread of control.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With