New submission from Zhiming Wang <zmwa...@gmail.com>:

I noticed that on Windows, socket operations like recv appear to always block 
SIGINT until it's done, so if a recv hangs, Ctrl+C cannot interrupt the 
program. (I'm a *nix developer investigating a behavioral problem of my program 
on Windows, so please excuse my limited knowledge of Windows.)

Consider the following example where I spawn a TCP server that stalls 
connections by 5 seconds in a separate thread, and use a client to connect to 
it on the main thread. I then try to interrupt the client with Ctrl+C.

    import socket
    import socketserver
    import time
    import threading


    interrupted = threading.Event()


    class HoneypotServer(socketserver.TCPServer):
        # Stall each connection for 5 seconds.
        def get_request(self):
            start = time.time()
            while time.time() - start < 5 and not interrupted.is_set():
                time.sleep(0.1)
            return self.socket.accept()


    class EchoHandler(socketserver.BaseRequestHandler):
        def handle(self):
            data = self.request.recv(1024)
            self.request.sendall(data)


    class HoneypotServerThread(threading.Thread):
        def __init__(self):
            super().__init__()
            self.server = HoneypotServer(("127.0.0.1", 0), EchoHandler)

        def run(self):
            self.server.serve_forever(poll_interval=0.1)


    def main():
        start = time.time()
        server_thread = HoneypotServerThread()
        server_thread.start()
        sock = socket.create_connection(server_thread.server.server_address)
        try:
            sock.sendall(b"hello")
            sock.recv(1024)
        except KeyboardInterrupt:
            print(f"processed SIGINT {time.time() - start:.3f}s into the 
program")
            interrupted.set()
        finally:
            sock.close()
            server_thread.server.shutdown()
            server_thread.join()


    if __name__ == "__main__":
        main()

On *nix systems the KeyboardInterrupt is processed immediately. On Windows, the 
KeyboardInterrupt is always processed more than 5 seconds into the program, 
when the recv is finished.

I suppose this is a fundamental limitation of Windows? Is there any workaround 
(other than going asyncio)?

Btw, I learned about SIGBREAK, which when unhandled seems to kill the process 
immediately, but that means no chance of cleanup. I tried to handle SIGBREAK 
but whenever a signal handler is installed, the behavior reverts to that of 
SIGINT -- the handler is called only after 5 seconds have passed.

(I'm attaching a socket_sigint_sigbreak.py which is a slightly expanded version 
of my sample program above, showing my attempt at handler SIGBREAK. Both

    python .\socket_sigint_sigbreak.py --sigbreak-handler interrupt

and

    python .\socket_sigint_sigbreak.py --sigbreak-handler exit

stall for 5 seconds.)

----------
components: Windows
files: socket_sigint_sigbreak.py
messages: 374580
nosy: paul.moore, steve.dower, tim.golden, zach.ware, zmwangx
priority: normal
severity: normal
status: open
title: SIGINT blocked by socket operations like recv on Windows
type: behavior
versions: Python 3.8
Added file: https://bugs.python.org/file49348/socket_sigint_sigbreak.py

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue41437>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to