TAGS :Viewed: 7 - Published at: a few seconds ago

[ Why my multithreaded Python webserver is failing? ]

I have built a small multithreaded web server with help of this and this. However my server thread runs only once and stops, instead of running forever. Following is my code :

import time
import BaseHTTPServer
import urlparse
import urllib 
import SocketServer
import threading

HOST_NAME = 'localhost'
PORT_NUMBER = 8089


class Handler(BaseHTTPServer.BaseHTTPRequestHandler):

    def do_HEAD(self):
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.end_headers()

    def do_GET(self):
        """ Respond to a GET request. """

        self.do_HEAD()

        if self.path == '/vmnum/':
            response = self.construct_message('Currently there are no VMs running')
            self.wfile.write(response)
        elif self.path == '/vmname/':
            respose = self.construct_message('Your VM is yet to be named')
            self.wfile.write(respose)
        else:
            response = self.construct_message()
            self.wfile.write(response)
        return


    def do_POST(self):
        """ Respond to a POST request """
        length = int(self.headers['Content-Length'])

        #http://stackoverflow.com/a/12731208/1382297
        post_data = urlparse.parse_qs(self.rfile.read(length).decode('utf-8'))
        thread_number = threading.currentThread().getName()
        lab_name = str(post_data.get('lab-name')[0])
        lab_author = str(post_data.get('lab-author')[0])

        message = "<p>You successfully created a VM named: " + lab_name + " at the location: " + lab_author + "</p><p>\
        \nYou have been served from the thread: " + thread_number
        respose = self.construct_message(message)

        self.wfile.write(respose)        
        return

    def construct_message(self, message=''):
        message_part1 = "<html><head><title>One VM Per Lab</title></head><body><p>Success!</p>"
        message_part2 = "<p>You accessed path: " + self.path + "</p>"
        message_part3 = "</body></html>"
        return message_part1 + message_part2 + message + message_part3

class ThreadedHTTPServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
    """Handle requests in a separate thread."""
    pass

if __name__ == '__main__':
    httpd = ThreadedHTTPServer((HOST_NAME, PORT_NUMBER), Handler)
    try:
        server_thread = threading.Thread(target=httpd.serve_forever)
        # Exit the server thread when the main thread terminates
        server_thread.daemon = True
        server_thread.start()
        print "Server Started - %s:%s with the thread :%s" % (HOST_NAME, PORT_NUMBER, server_thread.name)
    except KeyboardInterrupt:
        httpd.server_close()
    print "Server Stopped - %s:%s" % (HOST_NAME, PORT_NUMBER)

When I run the above script, I get the following:

Server Started - localhost:8089 with the thread :Thread-1
Server Stopped - localhost:8089

If I make my server non-multithreaded [i.e. it won't have a server thread, then it runs fine]. Note that it will be still multithreaded by spawning a new thread for every request

if __name__ == '__main__':
    httpd = ThreadedHTTPServer((HOST_NAME, PORT_NUMBER), Handler)
    print "Server Started - %s:%s" % (HOST_NAME, PORT_NUMBER)
    try:
        httpd.serve_forever()
    except KeyboardInterrupt:
        httpd.server_close()
    print "Server Stopped - %s:%s" % (HOST_NAME, PORT_NUMBER)

Answer 1


Your main thread needs to block on something. Otherwise it just calls server_thread.start() and then proceeds right along to calling print "Server stopped - ....

Consider putting a server_thread.join() after your print "Server Started... line.

See also http://docs.python.org/2/library/threading.html#threading.Thread.join

Answer 2


From the docs:

A thread can be flagged as a “daemon thread”. The significance of this flag is that the entire Python program exits when only daemon threads are left.

So as your main thread terminates with print "Server Stopped ... call, all your daemon threads are shut down.

Shortest, but probably not the best solution to pause execution flow and wait to keyboard interrupt, add infinite loop. Your daemon thread will die silently with your main thread.

try:
   while True:
       time.sleep(1)
except (KeyboardInterrupt, SystemExit):
    print "Server Stopped - %s:%s" % (HOST_NAME, PORT_NUMBER)