Reputation: 32439
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
.
Upvotes: 0
Views: 1150
Reputation: 8481
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.
Upvotes: 1