1

I start multiple servers using the following:

from threading import Thread
from SocketServer import ThreadingMixIn
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler

class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header("Content-type", "text/plain")
        self.end_headers()
        self.wfile.write("Hello World!")

class ThreadingHTTPServer(ThreadingMixIn, HTTPServer):
    pass

def serve_on_port(port):
    server = ThreadingHTTPServer(("localhost",port), Handler)
    server.serve_forever()

Thread(target=serve_on_port, args=[1111]).start()
Thread(target=serve_on_port, args=[2222]).start()

I want to stop these threads on KeyboardInterrupt. How can I do that?

Dan Getz
  • 8,774
  • 6
  • 30
  • 64
ghostcoder
  • 473
  • 1
  • 5
  • 17

2 Answers2

1

To stop one of these servers, you can use its shutdown() method. This means you will need a reference to the server from the code that catches the KeyboardInterrupt. For example:

servers = []
for port in [11111, 22222]:
    servers.append(ThreadingHTTPServer(("localhost",port), Handler))

for server in servers:
    Thread(target=server.serve_forever).start()

try:
    while True:
        time.sleep(1000000)
except KeyboardInterrupt:
    for server in servers:
        server.shutdown()
Dan Getz
  • 8,774
  • 6
  • 30
  • 64
  • Thanks! It does work in few cases but most of the time after the KeyboardInterrupt nothing happens. The documentation says "Tell the serve_forever() loop to stop and wait until it does." Is there a way to forcefully stop it? – ghostcoder Mar 09 '15 at 19:05
  • if `shutdown` doesn't return, that means your server is still handling something. – Jason Hu Mar 09 '15 at 19:54
1

You can kill lots of threads at the end of your program by defining them as daemon threads. To do this, set their daemon property to true. According to the documentation,

This must be set before start() is called, otherwise RuntimeError is raised. Its initial value is inherited from the creating thread; the main thread is not a daemon thread and therefore all threads created in the main thread default to daemon = False.

The entire Python program exits when no alive non-daemon threads are left.

So, something like this should work:

for port in [1111, 2222]:
    t = Thread(target=serve_on_port, args=[port])
    t.daemon = True
    t.start()

try:
    while True:
        time.sleep(1000000)
except KeyboardInterrupt:
    pass

Note that any threads that are non-daemon and still running will keep your program from exiting. If you have other threads that you also want to be killed on exit, set their daemon properties to True before starting them, too.

Community
  • 1
  • 1
Dan Getz
  • 8,774
  • 6
  • 30
  • 64
  • Thanks for the reply. I get the same results as your previous answer. I also added `except KeyboardInterrupt: print "Received keyboard interrupt. Shutting down servers." for server in servers: server.shutdown() print "b"` . After receiving ctrl-c it prints b but doesn't quit. Note that `print "b"` is outside the for loop. – ghostcoder Mar 11 '15 at 01:06
  • 1
    Well, what threads have been created that you didn't set `daemon = True` on before they started? Maybe one or more of those are still running. If they're being created in code you don't have control over or don't want to edit, you might be able to use the fact that threads created from daemon threads default to daemon. – Dan Getz Mar 11 '15 at 01:18
  • Also, you might want to either edit the code in this question, or post a new question, with a MCVE (see http://stackoverflow.com/help/mcve) that demonstrates the problem you encounter *after* one of the solutions here. Far as I can see, the problem shown by your example code in this question is solved by either of the solutions here. – Dan Getz Mar 11 '15 at 01:28
  • You are right. The no daemon threads were created by some other code. Thanks for the help! – ghostcoder Mar 11 '15 at 01:45