2012-05-22 2 views
2

Это то, что у меня есть:Как перезапустить экземпляр BaseHTTPServer?

http.py:

class HTTPServer(): 

    def __init__(self, port): 
     self.port = port 
     self.thread = None 
     self.run = True 
    def serve(self): 
     self.thread = threading.Thread(target=self._serve) 
     self.thread.start() 
    def _serve(self): 
     serverAddress = ("", self.port) 
     self.server = MyBaseHTTPServer(serverAddress,MyRequestHandler) 
     logging.log(logging.INFO, "HTTP server started on port %s"%self.port) 
     while self.run: 
      self.server.handle_request() 
    def stop(self): 
     self.run = False 
     self.server.server_close() 

Затем в другом файле, чтобы перезапустить его:

def restartHTTP(self): 
    try: 
     self.httpserver.stop() 
     reload(http) 
     self.httpserver = http.HTTPServer(80) 
     self.httpserver.serve() 
    except: 
     traceback.print_exc() 

Это дает мне адрес уже ошибки использования, так кажется, что HTTP-сервер не останавливается должным образом. Что еще мне нужно сделать, чтобы остановить его?

EDIT:

Где я называю restartHTTP:

def commandHTTPReload(self, parts, byuser, overriderank): 
    self.client.factory.restartHTTP() 
    self.client.sendServerMessage("HTTP server reloaded.") 

Я знаю, команда выполняется, потому что я получаю сообщение, что, как предполагается отправить.

+0

И поместите код, где вы вызываете restartHTTP. – Denis

+0

Вы действительно начали сервер на порту 80? – Triptych

+0

Да, я уверен, что это тот же порт, что и раньше. – Joseph

ответ

2

Вам просто нужно сообщить ОС, что вы действительно хотите повторно использовать порт сразу после его закрытия. Обычно он удерживается в закрытом состоянии на некоторое время, в случае появления каких-либо дополнительных пакетов. Вы делаете это с помощью SO_REUSEADDR:

mysocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 

... после открытия mysocket. Хорошее место, чтобы сделать это с HTTPServer может быть в переопределен server_bind метод:

def server_bind(self): 
    HTTPServer.server_bind(self) 
    self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 

Edit: После более внимательно посмотрел на свой код, я вижу, что ваша потоковая модель также, вероятно, вызывает проблемы здесь. Вы закрываете сокет в основном (?) Потоке, пока другой поток ожидает соединения в том же сокете (в accept()). У этой схемы нет четко определенной семантики, и я считаю, что она делает разные вещи на разных ОС. В любом случае, это то, что вам следует избегать, чтобы свести к минимуму путаницу (уже много чего нужно сделать в многопоточной программе). Ваш старый поток фактически не исчезнет, ​​пока не получит соединение и не обработает его запрос (потому что он не будет повторно проверять self.run до тех пор), и поэтому порт не может быть повторно привязан до этого.

На самом деле нет простого решения. Вы могли бы добавить канал связи между потоками, а затем использовать /poll() в потоке сервера, чтобы дождаться активности на любом из них, или вы могли бы затягивать вызовы accept() через короткое время, чтобы self.run чаще проверялся. Или вы можете подключить основной поток к самому гнезду для прослушивания. Но независимо от того, что вы делаете, вы, вероятно, приближаетесь к уровню сложности, когда вам стоит взглянуть на «реальный» httpd или сетевой фрейм, вместо того, чтобы сворачивать ваши собственные: apache, lighttpd, Tornado, Twisted и т. Д.

+0

Это не сработало. Кроме того, я думаю, что это не проблема (только), потому что я также попытался отложить запуск сервера после его завершения на 5 секунд, все еще не получив успеха. – Joseph

+0

Это (ожидание 5 секунд) не обязательно имеет здесь значение; обычно сокет будет зависать в 'TIME_WAIT', блокируя другие сокеты от привязки к одному и тому же порту, в два раза больше максимального времени жизни сегмента (так, 4 минуты).Вы все еще получаете ту же самую ошибку после добавления SO_REUSEADDR? –

+0

Да, это, похоже, не имеет значения. – Joseph

1

Для изящно остановить HTTPServer и закрыть розетку, следует использовать:

# Start server 
httpd = HTTPServer(...) 
httpd.serve_forever() 
# Stop server 
httpd.shutdown() 
httpd.server_close() 
Смежные вопросы