Signal SIGINT ignored during socket.accept

Chris Angelico rosuav at gmail.com
Thu Sep 10 22:01:24 EDT 2015


On Fri, Sep 11, 2015 at 6:12 AM, James Harris <james.harris.1 at gmail.com> wrote:
> Thanks for your help, Chris. Using select() is a very good option. I tried
> first without a timeout and even then this version of Windows does not
> recognise Control-C until after the select() call returns (which needs
> similar prompting as with the accept() call. However, select() with a
> timeout allows the code to work both on Windows and Linux. Hooray!
>
> For anyone else who is looking for this the earlier test code was changed to
>
> port = 8880
> import select
> import socket
> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
> s.setblocking(0)
> s.bind(("", port))
> s.listen(1)
> while 1:
>  ready = select.select((s,), (), (), 0.5)
>  #print '(ready %s)' % repr(ready)
>  if (ready[0]):
>    try:
>      endpoint = s.accept()
>    except socket.error, details:
>      print 'Ignoring socket error:', repr(details)
>      continue
>    print '(endpoint %s)' % repr(endpoint)
>    if endpoint:
>      break

(Your indentation is looking like a single space, here. I would
suggest indenting a bit more, for readability; but it might just be an
artefact of posting.)

This is what I meant when I said you would be polling. Effectively,
you wake up your program every half-second, check if Ctrl-C has been
pressed, and if it hasn't, you go back to sleep again. This is pretty
inefficient.

Assuming you don't need stdin for any other purpose, one solution
would be to spin off a thread that simply watches for a keyboard
signal. I tested this on Windows 7 with 2.7.10 and 3.4.3, and it
appears to work:

import socket
import threading

# Python 2/3 compat
try: input = raw_input
except NameError: pass

PORT = 8880
mainsock = socket.socket()
mainsock.bind(("", PORT))
mainsock.listen(1)

def console():
    """Constantly read from stdin and discard"""
    try:
        while "moar console": input()
    except (KeyboardInterrupt, EOFError):
        socket.socket().connect(("127.0.0.1",PORT))

threading.Thread(target=console).start()

while "moar sockets":
    s = mainsock.accept()
    print("New connection: %r" % s)
    # Do whatever you want with the connection
    s.close()


As long as you have _some_ thread reading from the console, you can
get woken up by Ctrl-C. When that happens, it simply fires off a quick
socket connection to itself, thus waking up the main thread; and then
the main thread sees the KeyboardInterrupt. (I'm not sure why, but
instead of seeing KeyboardInterrupt in the console thread, I've been
seeing EOFError. Since I don't particularly care to explore the
problem, I just wrote the except clause to catch both.)

This eliminates the polling, but you have to sacrifice stdin to do it.
It may be worth bracketing all of that code with a platform check -
don't bother doing all this unless you're on Windows. Up to you.

Stupid Windows.

ChrisA



More information about the Python-list mailing list