Linux C Socket: Blocked on Recv Call

Linux C Socket: Blocked on recv call

You have told "In my application i have created a thread for a simple http server, then from within my application
i tried to connect to http server but control is blocked/hanged on recv call."

That means the recv is never returning 0. Now when the recv function will
return a 0? ->When it gets a TCP FIN segment. It seems that your server is never
sending a TCP FIN segment to the client.
The reason that is most likely here is that, your client code needs modification.
You are sending data from from the client, but you are never sending the FIN,
so I assume that your server function is continuing forever and it had not
sent the FIN. This made the recv wait for ever.

In the current code perhaps the fix is to add a line

else {
/*Send the FIN segment, but we can still read the socket*/
shutdown(s, SHUT_WR);
/* read result & check */
ret=http_read_line(s,header,MAXBUF-1);

In this case the shutdown function sends the TCP FIN and the server function can return and possibly then it would do a proper close.

And on a proper close, the FIN from the server will be received by the client. This would make the recv return 0, instead of getting blocked for ever.

Now if you want to continue any further data transfer from the client, you need to again connect or may be you need to have some different algorithm.

I hope my explanation may help fix the current problem.

C socket blocking call

The behavior is literally unspecified: fcntl is not required to unblock any threads.

Linux just sets the flag in the file description struct file and returns without unblocking any blocked threads.

A thread already blocked in recv can be scheduled to run only if:

  • data to read becomes available;
  • or an error condition on the file descriptor is detected (FIN/RST, socket read timeout, TCP keep-alive failure, the file descriptor is closed by another thread);
  • or a signal is received and the signal disposition does not include SA_RESTART;
  • or it is pthread_cancelled.

The fact that you are trying to change flags of a file descriptor of another thread suggests that your design requires a review. Ideally, threads must not share any data and not poke at each other's state, rather they should use message passing to communicate with each other.

What could cause a non-blocking socket to block on `recv`?

socket() automatically sets O_RDWR on the socket with my operating system and compiler, but it appears that O_RDWR had accidentally gotten unset on the socket in question at the start of the program (which somehow allowed it to read fine if there was data to read, but block otherwise). Fixing that bug caused the socket to stop blocking. Apparently, both O_RDWR and O_NONBLOCK are required to avoid sockets blocking, at least on my operating system and compiler.

How to cleanly interrupt a thread blocking on a recv call?

So you have at least these possibilities:

(1) pthread_kill will blow the thread out of recv with errno == EINTR and you can clean up and exit the thread on your own. Some people think this is nasty. Depends, really.

(2) Make your client socket(s) non-blocking and use select to wait on input for a specific period of time before checking if a switch used between the threads has been set to indicated they should shut down.

(3) In combo with (2) have each thread share a pipe with the master thread. Add it to the select. If it becomes readable and contains a shutdonw request, the thread shuts itself down.

(4) Look into the pthread_cancel mechanism if none of the above (or variations thereof) do not meet your needs.

When recv blocks?

The behaviour of recv/read depends on the characteristics of the socket itself. If the socket is marked as non-blocking, these calls should immediately return EAGAIN/EWOULDBLOCK rather than blocking the process.

The socket can be marked as non-blocking prior to reading from it, usually via fcntl or ioctl.

What this excerpt from the manual says is that, basically, reads on both blocking and non-blocking sockets are not required to fill the whole buffer that is supplied. That is why it is important to check the result of the recv/read calls in order to know how much of the buffer contains the actual data and how much is garbage.

It is not a good idea at all to use blocking sockets in conjunction with the IO polling calls such as select/poll/epoll. Even if the polling call indicates that a particular socket is ready for reading, a blocking socket would sometimes still block.



Related Topics



Leave a reply



Submit