Shutdown socketserver serve_forever() in one-thread Python application
python, sockets, socketserver
Solution
You can start another thread locally, in your handler, and call `shutdown` from there.
Working demo:
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import SimpleHTTPServer
import SocketServer
import time
import thread
class MyHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
def do_POST(self):
if self.path.startswith('/kill_server'):
print "Server is going down, run it again manually!"
def kill_me_please(server):
server.shutdown()
thread.start_new_thread(kill_me_please, (httpd,))
self.send_error(500)
class MyTCPServer(SocketServer.TCPServer):
def server_bind(self):
import socket
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.bind(self.server_address)
server_address = ('', 8000)
httpd = MyTCPServer(server_address, MyHandler)
try:
httpd.serve_forever()
except KeyboardInterrupt:
pass
httpd.server_close()
Few notes:
- To kill server, do POST request to `http://localhost:8000/kill_server`.
- I create function which calls `server.shutdown()` and run it from another thread to solve the problem we discuss.
- I use advice from Binding Socket: “Address already in use” to make socket instantly avaliable for reuse (you can run server again without having [Errno 98] Address already in use error). With stock TCPServer you will have to wait for connection to timeout to run you server again.
Problem
I know that socketserver has a method `shutdown()` which causes server to shut down but this only works in multiple threads application since the shutdown needs to be called from different thread than the thread where `serve_forever()` is running. My application handles only one request at time so I do not use separate threads for handling requests and I am unable to call `shutdown()` because it causes deadlock (it's not in the docs but it's stated directly in the source code of socketserver). I will paste here a simplified version of my code for better understanding: ``` import socketserver class TCPServerV4(socketserver.TCPServer): address_family = socket.AF_INET allow_reuse_address = True class TCPHandler(socketserver.BaseRequestHandler): def handle(self): try: data = self.request.recv(4096) except KeyboardInterrupt: server.shutdown() server = TCPServerV4((host, port), TCPHandler) server.server_forever() ``` I am aware that this code is not working. I just wanted to show you the thing I would like to accomplish - to shutdown server and quit the application while waiting for incoming data when the user presses CtrlC.