I believe the OP's intent is to shut down the server from the request handler and I think that the KeyboardInterrupt
aspect of his code is just confusing things.
Pressing CtrlC from the shell where the server is running will succeed in shutting it down without doing anything special. You can't press CtrlC from a different shell and expect it to work, and I think that notion may be where this confusing code is coming from. There is no need to handle the KeyboardInterrupt
in handle()
as the OP tried, or around serve_forever()
as another suggested. If you do neither, it works as expected.
The only trick here -- and it is tricky -- is telling the server to shutdown from the handler without deadlocking.
As the OP explained and showed in his code, he is using a single threaded server, so the user who suggested to shut it down in the "other thread" is not paying attention.
I dug around the SocketServer
code and discovered that the BaseServer
class, in its effort to work with the threaded mixins available in this module, actually makes it more difficult to use with non-threaded servers, by using a threading.Event
around the loop in serve_forever
.
So, I wrote a modified version of serve_forever
for single-threaded servers which makes it possible to shut down the server from the request handler.
import SocketServer
import socket
import select
class TCPServerV4(SocketServer.TCPServer):
address_family = socket.AF_INET
allow_reuse_address = True
def __init__(self, server_address, RequestHandlerClass):
SocketServer.TCPServer.__init__(self, server_address, RequestHandlerClass)
self._shutdown_request = False
def serve_forever(self, poll_interval=0.5):
"""provide an override that can be shutdown from a request handler.
The threading code in the BaseSocketServer class prevented this from working
even for a non-threaded blocking server.
"""
try:
while not self._shutdown_request:
# XXX: Consider using another file descriptor or
# connecting to the socket to wake this up instead of
# polling. Polling reduces our responsiveness to a
# shutdown request and wastes cpu at all other times.
r, w, e = SocketServer._eintr_retry(select.select, [self], [], [],
poll_interval)
if self in r:
self._handle_request_noblock()
finally:
self._shutdown_request = False
class TCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
data = self.request.recv(4096)
if data == "shutdown":
self.server._shutdown_request = True
host = 'localhost'
port = 52000
server = TCPServerV4((host, port), TCPHandler)
server.serve_forever()
If you send the string 'shutdown'
to the server, the server will end its serve_forever
loop. You can use netcat to test this:
printf "shutdown" | nc localhost 52000