Sending data through broken pipe

Question:

When I connect a socket to a server socket, and the server socket at a given time shuts down, I get a BrokenPipeError on the client side. But not the next time I try to send something, but the time after that.

Here a SSCCE:

Server:

#! /usr/bin/python3

import socket

s = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind ( ('', 10100) )
s.listen (1)
print ('Waiting on client')
client, _ = s.accept ()
print ('Accepted')
data = b''
done = False
while not done:
    data += client.recv (4096)
    msgs = data.split (b'r')
    for msg in msgs [:-1]:
        print ('received {}'.format (msg) )
        done = msg == b'exit'
    data = msgs [-1]
s.close ()
print ('Server down')

Client:

#! /usr/bin/python3

import socket

s = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
print ('Connecting')
s.connect ( ('localhost', 10100) )
print ('Connected')
for msg in [b'ping', b'pang', b'exit', b'ping', b'pang']:
    print ('Sending {}'.format (msg) )
    sent = s.send (msg + b'r')
    print ('Sent {}. {} bytes transmitted'.format (msg, sent) )
    input ('>> ')

I start up the server, then the client and hit enter to step through the messages.

The server output is:

Waiting on client
Accepted
received b'ping'
received b'pang'
received b'exit'
Server down

The client output is:

Connecting
Connected
Sending b'ping'
Sent b'ping'. 5 bytes transmitted
>> 
Sending b'pang'
Sent b'pang'. 5 bytes transmitted
>> 
Sending b'exit'
Sent b'exit'. 5 bytes transmitted
>> 
Sending b'ping'
Sent b'ping'. 5 bytes transmitted
>> 
Sending b'pang'
Traceback (most recent call last):
  File "./client.py", line 10, in <module>
    sent = s.send (msg + b'r')
BrokenPipeError: [Errno 32] Broken pipe

Why do I get the BrokenPipeError after the last pang and not after the ping?

Why does send return 5 when sending the ping after the exit?

Why is the pipe not broken immediately after the server is down?


EDIT: After having sent exit, I don’t hit enter on the client console unless the server console has already printed Server down.

Asked By: Hyperboreus

||

Answers:

The send function only ensures that the data has been transferred to the socket buffer. When the server closes it sends a FIN,ACK packet to which the client replies only ACK. The socket from client side will not be closed until the client calls the close method itself too. The connection is then "Half-Open".

When the client sends again data to the closed server socket, the server replies with RST to which the client is expected to abort the connection. See https://www.rfc-editor.org/rfc/rfc793#page-33 on Half-Open Connections and Other Anomalies. However, the socket is closed after the send method has returned. That’s why only the next send will crash on BrokenPipe, as the connection is now closed from the client side too.

Answered By: Cilyan
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.