[New-bugs-announce] [issue19530] cross thread shutdown of UDP socket exhibits unexpected behavior

mpb report at bugs.python.org
Sat Nov 9 04:57:48 CET 2013


New submission from mpb:

I have a multi-threaded application.
A background thread is blocked, having called recvfrom on a UDP socket.
The main thread wants to cause the background thread to unblock.
With TCP sockets, I can achieve this by calling:
sock.shutdown (socket.SHUT_RD)

When I try this with a UDP socket, the thread calling shutdown raises an OS Error (transport end point not connected).

The blocked thread does unblock (which is helpful), but recvform appears to return successfully, returning a zero length byte string, and a bogus address!

(This is the opposite of the TCP case, where the blocked thread raises the exception, and the call to shutdown succeeds.)

In contrast, sock.close does not cause the blocked thread to unblock.  (This is the same for both TCP and UDP sockets.)

I suspect Python is just exposing the underlying C behavior of shutdown and recvfrom.  I'd test it in C, but I'm not fluent in writing multi-threaded code in C.

It would be nice if the recvfrom thread could raise some kind of exception, rather than appearing to return successfully.  It might also be worth reporting this bug upstream (where ever upstream is for recvfrom).  I'm running Python 3.3.1 on Linux.

See also this similar bug.
http://bugs.python.org/issue8831

The Python socket docs could mention that to unblock a reading thread, sockets should be shutdown, not closed.  This might be implied in the current docs, but it could be made explicit.  See:

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

For example, the following sentence could be appended to the Note at the above link.  "Note: (...)  Specifically, in multi-threaded programming, if a thread is blocked performing a read or write on a socket, calling shutdown from another thread will unblock the blocked thread.  Unblocking via shutdown seems to work with TCP sockets, but may result in strange behavior with UDP sockets."

Here is sample Python code that demonstrates the behavior.

import socket, threading, time

sock = socket.socket (socket.AF_INET, socket.SOCK_DGRAM)
sock.bind (('localhost', 8000))

def recvfrom ():
  for i in range (2) :
    print ('recvfrom  blocking ...')
    recv, remote_addr = sock.recvfrom (1024)
    print ('recvfrom  %s  %s' % (recv, remote_addr))

thread = threading.Thread ( target = recvfrom )
thread.start ()
time.sleep (0.5)

sock2 = socket.socket (socket.AF_INET, socket.SOCK_DGRAM)
sock2.sendto (b'test', ('localhost', 8000))

time.sleep (0.5)

try:  sock.shutdown (socket.SHUT_RD)
except OSError as exc :  print ('shutdown  os error  %s' % str (exc))

sock.close ()

thread.join ()
print ('exiting')


----

And here is the output of the above code:

recvfrom  blocking ...
recvfrom  b'test'  ('127.0.0.1', 48671)
recvfrom  blocking ...
shutdown  os error  [Errno 107] Transport endpoint is not connected
recvfrom  b''  (59308, b'\xaa\xe5\xec\xde3\xe6\x82\x02\x00\x00\xa8\xe7\xaa\xe5')
exiting

----------
components: IO
messages: 202457
nosy: mpb
priority: normal
severity: normal
status: open
title: cross thread shutdown of UDP socket exhibits unexpected behavior
type: behavior
versions: Python 3.3

_______________________________________
Python tracker <report at bugs.python.org>
<http://bugs.python.org/issue19530>
_______________________________________


More information about the New-bugs-announce mailing list