3

I've got a problem with SocketServer.TCPServer. I'm running a server in a thread. Watching a directory tree with Watchdog. When "on_any_event" runs I need to take down the server and start it again. Unfortunately I can't get SocketServer.TCPServer to reuse the address. I've checked the SocketServer.py file and if allow_reuse_address is True it is supposed to set socket.SO_REUSEADDR to 1. It still fails with error: [Errno 98] Address already in use though. Sleeping for 10 secs before retrying doesn't help either. Any help?

class Server(SocketServer.TCPServer):
    allow_reuse_address = True

class ChangeHandler(FileSystemEventHandler):
    def __init__(self):
        FileSystemEventHandler.__init__(self)
        self.rebuild()

    def on_any_event(self, event):
        print event
        self.httpd.shutdown()
        self.t.join()
        self.rebuild()

    def rebuild(self):
        self.t, self.httpd = runserver()

def runserver():
    handler = SimpleHTTPServer.SimpleHTTPRequestHandler
    httpd = Server((HOST, PORT), handler, bind_and_activate=False)
    httpd.server_bind()
    httpd.server_activate()
    t = threading.Thread(target=httpd.serve_forever)
    t.daemon = True
    t.start()
    print "Live at http://{0}:{1}".format(HOST, PORT)
    return t, httpd

if __name__ == "__main__":
    handler = ChangeHandler()
    observer = Observer()
    observer.schedule(handler, path=ROOT, recursive=True)
    observer.start()

    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        observer.stop()
    observer.join()
tshepang
  • 12,111
  • 21
  • 91
  • 136
vascop
  • 4,972
  • 4
  • 37
  • 50

2 Answers2

4

TCPServer implements the undocumented method server_close(), call this before or after self.t.join() in your event handler, since that is what will actually close the underlying socket. As written it looks like you may be potentially leaking a socket.

def on_any_event(self, event):
    print event
    self.httpd.shutdown()
    self.httpd.server_close() # actually close the socket
    self.t.join()
    self.rebuild()

Until you close the socket the address actually is in use.

grieve
  • 13,220
  • 10
  • 49
  • 61
3

Adding a self.httpd.server_close() after self.httpd.shutdown() did the trick.

vascop
  • 4,972
  • 4
  • 37
  • 50