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 isclose
d by another thread); - or a signal is received and the signal disposition does not include
SA_RESTART
; - or it is
pthread_cancel
led.
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
Difference Between Source and ./ Execution of Linux Scripts
Comparison of Cat Pipe Awk Operation to Awk Command on a File
Jupyter Lab - Suppress Console Output
Executable Object Files and Virtual Memory
Start Docker-Compose Automatically on Ec2 Startup
Sched_Fifo Higher Priority Thread Is Getting Preempted by the Sched_Fifo Lower Priority Thread
Delete the Word Whose Length Is Less Than 2 in Bash
How to Print Current Time in Kernel
Error When Installing Opencv on Ubuntu 14.04
Interacting with Files from Multiple Directories via Bash Script
Using Sed to Print Between Two Patterns
Shell Function Does Not Return Values Greater Than 255
Sed: Matching on 2 Patterns on the Same Line
Wget: Unsupported Scheme on Non-Http Url
How to Read from Text File Line-By-Line and Split the Line by a Character
Phusion Passenger Nginx Module Installer V3.0.17 Issue on Debian 6.0.5 Amd64 Due to Broken Package
Is an Operating System Kernel an Interpeter for All Other Programs