Of sockets, hanging, and Windows

John Arbash Meinel john at arbash-meinel.com
Thu Oct 20 13:24:09 UTC 2011


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

I just ran into a new failure today, trying to build a SocketServer
handler. I figured I'd share the info with the larger group.

Basically, however 'socket.recv()' is implemented on Windows, it does
not return if you call socket.close(). In fact, it can actually read
more bytes from the socket (that you ostensibly just closed). They
actually even indicate that in the python docs:

http://docs.python.org/library/socket.html#socket.socket.close

It releases the resource, but does not close the connection. It even
mentions that you should use 'shutdown' first, however even that is
not enough.

A fairly simple test case for it:

>>> import socket, threading, sys s = socket.socket() 
>>> s.bind(('127.0.0.1', 0)) s.listen(1) c = socket.socket() 
>>> c.connect(s.getsockname()) r = s.accept()[0] def
>>> recv_and_write_and_recv():
...   sys.stderr.write('waiting to receive\n')
...   m = r.recv(1024)
...   sys.stderr.write('got %r\n' % (m,))
...   r.sendall(m)
...   sys.stderr.write('waiting for more\n')
...   m = r.recv(1024)
...   sys.stderr.write('got more: %r\n' % (m,))
...
>>> t = threading.Thread(target=recv_and_write_and_recv) t.start()
waiting to receive

>>> c.sendall('foo\n')
got 'foo\n'
waiting for more
>>> print c.recv(1024)
foo

>>> r.shutdown(socket.SHUT_RDWR) r.close() c.sendall('byebye\n')
got more: 'byebye\n'


Now, *if* you have done socket.close() (and maybe socket.shutdown())
before you get to socket.recv(), then it will give you some sort of
EBADF exception. And maybe you'd get the same result if
socket.sendall() was blocked because the content string was too long,
(though I wasn't able to block it with a 4MB sendall() call...)

The only way I can see to reliably actually cause the socket to stop
is to close the *client* socket (or add a timeout, etc).

I'm guessing that isn't true on all platforms. On 'devpad', I get:
got more: ''

Indicating that it did see the socket as closed, and was happy to let
us return.


Even better, though, when I run it in a different terminal, I don't
get all of the messages printed out! (though that seems to be a
writing-to-stderr/stdout vs python interpreter deciding what goes on
the screen) Though t.isAlive() returns the expected values (it is
alive while waiting for the last receive.)

Anyway, closing server-side sockets may not do what you think it does
(like actually close them. :)

Certainly, it doesn't seem to interrupt socket.recv() in such a way
that the recv notices the connection is closed.

John
=:->
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Cygwin)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAk6gIPkACgkQJdeBCYSNAAM3pwCfcG6PUf4cVWTLNVjl6iqQgE6G
ez8An1NbA+OzG0zOMxuSzVcKJHWj5iMJ
=fFP6
-----END PGP SIGNATURE-----



More information about the bazaar mailing list