The python3 socket programming howto presents this code snippet
class MySocket:
"""demonstration class only
- coded for clarity, not efficiency
"""
def __init__(self, sock=None):
if sock is None:
self.sock = socket.socket(
socket.AF_INET, socket.SOCK_STREAM)
else:
self.sock = sock
def connect(self, host, port):
self.sock.connect((host, port))
def mysend(self, msg):
totalsent = 0
while totalsent < MSGLEN:
sent = self.sock.send(msg[totalsent:])
if sent == 0:
raise RuntimeError("socket connection broken")
totalsent = totalsent + sent
def myreceive(self):
chunks = []
bytes_recd = 0
while bytes_recd < MSGLEN:
chunk = self.sock.recv(min(MSGLEN - bytes_recd, 2048))
if chunk == b'':
raise RuntimeError("socket connection broken")
chunks.append(chunk)
bytes_recd = bytes_recd + len(chunk)
return b''.join(chunks)
where the send loop is interrupted if the socket send
method returns 0.
The logic behind this snippet is that when the send
method returns '0 bytes sent', the sending side of a socket connection should give up its efforts to send data. This is for sure true for the recv
method, where zero bytes read for a socket in blocking mode should be interpreted as EOF
, and therefore the reading side should give up.
However I cannot understand under which situations the send
method could return zero. My understanding of python sockets is that send
returns immediately due to buffering at the OS level. If the buffer is full send
will block, or if the connections is closed at the remote side, an exception is raised.
Finally suppose send
returns zero without raising an exception: does this really indicate that all future send
calls will return zero?
I've done some testing (although using only socket connected to ::1
on OS X) and was not able to find a situation in which send
returns 0.
Edit
The HOWTO states:
But if you plan to reuse your socket for further transfers, you need to realize that there is no EOT on a socket. I repeat: if a socket send or recv returns after handling 0 bytes, the connection has been broken. If the connection has not been broken, you may wait on a recv forever, because the socket will not tell you that there’s nothing more to read (for now).
It is pretty easy to find a situation in which recv
returns 0: when the remote (sending) side calls socket.shutdown(SHUT_WR)
, further recv
on the receiving side will return 0
and not raise any exception.
I'm looking for a concrete example where you can show that receiving 0 zero from send
indicates a broken connection (which will continue to return 0 on send.)
Upon seeing the question I was somehow stunned, because a send
C call can return 0 bytes and the connection is of course still alive (the socket cannot simply send more bytes at that given moment in time)
I decided to "use the source" and unless I am very wrong (which can always be and often is) this is a bug in the HOWTO.
Chain:
send
is an alias for sock_send
sock_send
calls in turn sock_call
sock_call
calls in turn sock_call_ex
sock_call
calls in turn sock_send_impl
(which has been passed down the chain starting with sock_send
)Unwinding:
sock_send_impl
returns true
or false
(1 or 0) with return (ctx->result >= 0)
sock_call_ex
returns
-1
if sock_send_impl
returns false
0
if sock_send_impl
returns true
sock_call
returns this value transparently.
sock_send
returns NULL
for a -1
(because an error has been set and an exception will be raised)
returns ctx->result
for 0
from sock_call
And ctx->result
is the number of bytes written by the C call send
in sock_send_impl
.
The chain shows that if 0
bytes have been sent, there is no error and this actually is a potential real life socket situation.
If my logic is wrong, someone please let me know.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With