7

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 ''
Community
  • 1
  • 1
replay
  • 3,569
  • 3
  • 21
  • 30
  • Sockets do not immediately close after the application exits. – Anfernee May 19 '16 at 18:14
  • thx @AJPennster even if i wait for the CLOSE_WAIT timeout it just keeps looping – replay May 19 '16 at 18:20
  • But a CLOSE_WAIT still doesn't mean the socket has closed, just waiting to be closed. Try killing terminal 1 and see what happens. – Anfernee May 19 '16 at 19:36
  • I'm not exactly sure of the Python syntax but calling `Shutdown()` and `Close()` on the socket may work better for you – pay May 19 '16 at 20:47

2 Answers2

9

This is by design in the underlying operating system recv system call: a read on a socket closed on peer, or as soon as the peer used a shutdown(s, SHUT_WR) to indicate it will no send anything more, returns immediately with a length of 0 bytes.

That is the only case when you have a successful read of 0 bytes, because while the peer socket remains open, a successful read returns at least one byte on a blocking socket or a E_AGAIN or E_WOULDBLOCK error on a non blocking socket.

TL/DR: there is no anomaly in observed behaviour

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
2

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.

Steffen Ullrich
  • 114,247
  • 10
  • 131
  • 172