mauro.stettler mauro.stettler - 6 months ago 34
Python Question

`sock.recv()` returns empty string when connection is dead on non-blocking socket

I have a non-blocking socket in Python called

sock
. According to my understanding the
recv()
method should raise an exception if the connection has been closed by the peer, but it returns an empty string (
''
) and I don't know why.

This is the script I test with (from here):

import sys
import socket
import fcntl, os
import errno
from time import sleep

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1',9999))
fcntl.fcntl(s, fcntl.F_SETFL, os.O_NONBLOCK)

while True:
try:
msg = s.recv(4096)
print("got data '{msg}'".format(msg=msg))
except socket.error, e:
err = e.args[0]
if err == errno.EAGAIN or err == errno.EWOULDBLOCK:
sleep(1)
print 'No data available'
continue
sys.exit(1)


If the peer closes the connection this socket is supposed to raise
socket.error
on
recv()
, but instead it only returns
''
.

I test it this way, using two terminals:

# Terminal 1
~$ nc -l -p9999

# Terminal 2
~$ python ./test_script.py

# Terminal 1
typingsomestring

# Terminal 2
No data available
No data available
No data available
got data 'typingsomestring
'
No data available
No data available

# Terminal 1
Ctrl+C # (killing nc)

# Terminal 2
got data ''
got data ''
got data ''
got data ''
got data ''
got data ''
got data ''
got data ''
got data ''
got data ''
got data ''
got data ''
got data ''
got data ''
got data ''
got data ''
got data ''
got data ''
got data ''

Answer

recv throws an exception if an error occurred. Closing a socket by the peer is no error, but is a normal behavior. In fact it is not even a full close: the peer only indicates that it will not send any more data, but it might still receive data. The TCP connection is only closed if both sides indicate that they will not send any more data, i.e. each side has send the FIN.