Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Broken pipe only at the second send on a closed socket

I'm testing a client-server communication through a TCP socket. I wrote the server in C and I'm running it on a Linux machine and I'm using nc as a client for test.

The server, after an initial exchange of messages with the client, sends some messages periodically to the client without getting any response.

If I kill the client, I expect that the first send() done by the server fails with EPIPE error but this is turns out only at the second send() after the client has gone! The first send() after I killed the client is able to successfully send 1100 bytes to the (I suppose closed) socket. The following send() operation ends with EPIPE as exepcted.

Is there someone who can explain me this behaviour? Is it due to the fact that I write to the TCP/IP stack so it's up to the stack to deliver when it can? If so, how can I check the connection status? To be sure the peer is still there.

like image 434
Igor Avatar asked Sep 04 '12 13:09

Igor


1 Answers

Normal TCP Connection is a four way handshake.

http://en.wikipedia.org/wiki/Transmission_Control_Protocol

When you are killing the client the FIN segment is sent from the client side to the server and the server protocol stack sends the ACK.

Here if the server tried to read data, the read call would return a value of 0, so your server program can understand that the peer has closed and normally would close the connection socket after this. This would allow the FIN from the server side to be sent and normal 4 way handshake would get completed after the receipt of the last ACK from the client side.

(Pl read Q 2.1 of http://www.faqs.org/faqs/unix-faq/socket/)

But here you are writing data from the server, so the server is getting a RESET from the client only after sending data. So you are getting the error after the first send operation that is on the second send.

So, pl. try closing the connection from the client side abruptly instead of 4 way handshake, by setting the linger option and timeout to 0, so that you can get a error(may be different from EPIPE) on the first call of send on the server side.(This is not a recommended practice but only for your understanding in this particular case)

Try the following option of nc, nc -L 0 to set the linger option and timeout to 0

(I have not tried this option of nc, pl. check for details in this link http://docs.oracle.com/cd/E23824_01/html/821-1461/nc-1.html)

Example of nc from the above site,

Connect to TCP port, send some data and terminate the connection with 
TCP RST segment 
(instead of classic TCP closing handshake) by setting the linger option and 
timeout to 0:

$ echo "foo" | nc -L 0 host.example.com 22
like image 60
Tanmoy Bandyopadhyay Avatar answered Sep 23 '22 21:09

Tanmoy Bandyopadhyay