2012-04-04 12 views
5

Napisałem prosty serwer HTTP do obsługi żądań postu:serwer HTTP zawiesza się podczas przyjmowania pakietów

class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler): 
    def do_POST(self): 
     ctype, pdict = cgi.parse_header(self.headers.getheader('content-type')) 
     postvars = {} 
     try: 
      if ctype == 'application/x-www-form-urlencoded': 
       length = int(self.headers.getheader('content-length')) 
       postvars = cgi.parse_qs(self.rfile.read(length), keep_blank_values=1) 

      self.send_response(200) 
      self.send_header("Content-type", "text") 
      self.send_header("Content-length", str(len(body))) 
      self.end_headers() 
      self.wfile.write(body) 
     except: 
      print "Error" 


def httpd(handler_class=MyHandler, server_address = ('2.3.4.5', 80)): 
    try: 
     print "Server started" 
     srvr = BaseHTTPServer.HTTPServer(server_address, handler_class) 
     srvr.serve_forever() # serve_forever 
    except KeyboardInterrupt: 
     server.socket.close() 


if __name__ == "__main__": 
    httpd() 

Serwer działa poprawnie, ale czasami po prostu zawiesza. Po naciśnięciu CTRL + C daje następujący błąd, a następnie kontynuuje odbieranie danych:

Exception happened during processing of request from ('1.1.1.2', 50928) 
Traceback (most recent call last): 
    File "/usr/lib/python2.6/SocketServer.py", line 281, in _handle_request_noblock 
    self.process_request(request, client_address) 
    File "/usr/lib/python2.6/SocketServer.py", line 307, in process_request 
    self.finish_request(request, client_address) 
    File "/usr/lib/python2.6/SocketServer.py", line 320, in finish_request 
    self.RequestHandlerClass(request, client_address, self) 
    File "/usr/lib/python2.6/SocketServer.py", line 615, in __init__ 
    self.handle() 
    File "/usr/lib/python2.6/BaseHTTPServer.py", line 329, in handle 
    self.handle_one_request() 
    File "/usr/lib/python2.6/BaseHTTPServer.py", line 312, in handle_one_request 
    self.raw_requestline = self.rfile.readline() 
    File "/usr/lib/python2.6/socket.py", line 406, in readline 
    data = self._sock.recv(self._rbufsize) 
KeyboardInterrupt 

Czy ktoś może mi powiedzieć jak rozwiązać ten problem? Nie mogę zrozumieć błędów.

+0

Czy to naprawdę kod, który używasz? To zwisające 'except 'wygląda na błąd składni. – alberge

+0

Tęsknię za stwierdzeniem podczas kopiowania. Przepraszam za to. – Bruce

+0

Czy jesteś pewien, że klient nie powoduje problemu (np. Łącząc się i nie wysyłając niczego lub nieograniczonej ilości danych)? – katzenversteher

Odpowiedz

10

ja całkowicie przepisał moje rozwiązanie w celu ustalenia dwie wady:

  • Można go traktować limit czasu, nawet jeśli klient jest otwarty tylko połączenie, ale nie zacząć komunikować.
  • Jeśli klient otworzy połączenie, nowy proces serwera zostanie rozwidlony. Powolny klient nie może blokować innych.

Opiera się na kodzie w jak największym stopniu. Jest to teraz kompletne niezależne demo. Jeśli otworzysz przeglądarkę pod http://localhost:8000/ i napisz "symuluj błąd", aby utworzyć i naciśnij przycisk "Wyślij", symuluje on błąd środowiska wykonawczego.

import BaseHTTPServer 
import SocketServer 
import cgi 


class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler): 
    def do_POST(self): 
     ctype, pdict = cgi.parse_header(self.headers.getheader('content-type')) 
     postvars = {} 
     try: 
      if ctype == 'application/x-www-form-urlencoded': 
       length = int(self.headers.getheader('content-length')) 
       postvars = cgi.parse_qs(self.rfile.read(length), 
         keep_blank_values=1) 
       assert postvars.get('foo', '') != ['simulate error'] 
      body = 'Something' 
      self.send_response(200) 
      self.send_header("Content-type", "text") 
      self.send_header("Content-length", str(len(body))) 
      self.end_headers() 
      self.wfile.write(body) 
     except: 
      self.send_error(500) 
      raise 

    def do_GET(self): 
     # demo for testing POST by web browser - without valid html 
     body = 'Something\n<form method="post" action="http://%s:%d/">\n' \ 
       '<input name="foo" type="text"><input type="submit"></form>\n'\ 
       % self.server.server_address 
     self.send_response(200) 
     self.send_header("Content-type", "text/html") 
     self.send_header("Content-length", str(len(body))) 
     self.end_headers() 
     self.wfile.write(body) 


class ForkingHTTPServer(SocketServer.ForkingMixIn, BaseHTTPServer.HTTPServer): 
    def finish_request(self, request, client_address): 
     request.settimeout(30) 
     # "super" can not be used because BaseServer is not created from object 
     BaseHTTPServer.HTTPServer.finish_request(self, request, client_address) 


def httpd(handler_class=MyHandler, server_address=('localhost', 8000)): 
    try: 
     print "Server started" 
     srvr = ForkingHTTPServer(server_address, handler_class) 
     srvr.serve_forever() # serve_forever 
    except KeyboardInterrupt: 
     srvr.socket.close() 

if __name__ == "__main__": 
    httpd() 

Rozwidlenie można wyłączyć np. debugowanie przez usunięcie klasy SocketServer.ForkingMixIn z kodu.

+0

Niesamowita odpowiedź. Szukałem dokładnie tego! – Bruce

+0

Jak mogę zamknąć połączenie klienta? Próbowałem self.rfile._sock.close(), ale to nie pomaga ... Limit czasu nie działa. Chcę przymusowo zamknąć połączenie, gdy wyjątek dzieje się w self.rfile.read() ... Jestem otwarty na wszelkie sugestie ... – Bruce

+0

Napisałem kompletne rozwiązanie zamiast porady. – hynekcer

Powiązane problemy