2008-11-06 12 views
29

मैं अपने HTTPServer को एक अलग धागे में चला रहा हूं (थ्रेडिंग मॉड्यूल का उपयोग करके जिसमें धागे को रोकने का कोई तरीका नहीं है ...) और जब मुख्य थ्रेड भी बंद हो जाता है तो सेवा अनुरोध करना बंद करना चाहते हैं।बेसHTTPRequestHandler उपclass में BaseHTTPServer.serve_forever() को कैसे रोकें?

अजगर प्रलेखन कहा गया है कि BaseHTTPServer.HTTPServerSocketServer.TCPServer का एक उपवर्ग है, जो एक shutdown विधि का समर्थन करता है, लेकिन यह HTTPServer में याद आ रही है।

पूरे BaseHTTPServer मॉड्यूल बहुत कम प्रलेखन :(है

उत्तर

18

मैं कह रही है कि द्वारा शुरू कर देना चाहिए "मैं शायद यह अपने आप ऐसा नहीं करेंगे, लेकिन मैं अतीत में नहीं है।" Serve_forever (SocketServer.py से) विधि इस प्रकार है:

def serve_forever(self): 
    """Handle one request at a time until doomsday.""" 
    while 1: 
     self.handle_request() 

आप (उपवर्ग में) while self.should_be_running साथ while 1 की जगह सकता है, और है कि मूल्य को संशोधित एक अलग धागे से की तरह कुछ:।

def stop_serving_forever(self): 
    """Stop handling requests""" 
    self.should_be_running = 0 
    # Make a fake request to the server, to really force it to stop. 
    # Otherwise it will just stop on the next request. 
    # (Exercise for the reader.) 
    self.make_a_fake_request_to_myself() 
,210

संपादित करें: मैं वास्तविक कोड मैं समय पर इस्तेमाल किया अप खोदा:

class StoppableRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer): 

    stopped = False 
    allow_reuse_address = True 

    def __init__(self, *args, **kw): 
     SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(self, *args, **kw) 
     self.register_function(lambda: 'OK', 'ping') 

    def serve_forever(self): 
     while not self.stopped: 
      self.handle_request() 

    def force_stop(self): 
     self.server_close() 
     self.stopped = True 
     self.create_dummy_request() 

    def create_dummy_request(self): 
     server = xmlrpclib.Server('http://%s:%s' % self.server_address) 
     server.ping() 
+0

मुझे लगता है कि आप "self.erve_forever()" को "self.stopped = True" के बाद कॉल कर सकते हैं और "create_dummy_request (self)" को लागू करने से बच सकते हैं। यह अब तक मेरे लिए काम करता है, लेकिन वहां एक सूक्ष्मता हो सकती है जिसे मैं याद कर रहा हूं। –

+1

जहां तक ​​मैं पाइथन 2.7 में 'बेससेवर.serve_forever() 'स्रोतों को देख रहा हूं, मुझे लगता है कि यह पहले से ही एक ध्वज लागू किया गया है,' __shutdown_request', प्लस' __is_shut_down' 'threading.Event' शीर्ष पर। तो मैं यहां देखे गए वास्तविक उत्तर 'allow_reuse_address = True' लाइन है। –

18

मेरी अजगर 2.6 स्थापना में, मैं अंतर्निहित TCPServer पर कॉल कर सकते हैं - अपने HTTPServer अंदर अभी भी वहाँ यह:

TCPServer.shutdown 


>>> import BaseHTTPServer 
>>> h=BaseHTTPServer.HTTPServer(('',5555), BaseHTTPServer.BaseHTTPRequestHandler) 
>>> h.shutdown 
<bound method HTTPServer.shutdown of <BaseHTTPServer.HTTPServer instance at 0x0100D800>> 
>>> 
+0

आह। हाँ, और मैं * 2.6 दस्तावेज़ पढ़ रहा हूं - हां, मैं 2.5 चला रहा हूं। ओह। मुझे मूर्ख –

+4

ध्यान दें कि शटडाउन के बाद भी, सॉकेट अभी भी इंटरफ़ेस/पोर्ट (पायथन v2.7 पर परीक्षण) पर सुनेंगे। आपको यह भी कॉल करना चाहिए: 'h.socket.close()'। –

15

मुझे लगता है कि आप [serverName].socket.close()

+2

यह एकमात्र तरीका था जो मेरे लिए काम करता था, सर्वर.शूटडाउन() के साथ कुछ_फ्लैग नहीं होने पर बाधा डालने का प्रयास करता था। केवल socket.close() वांछित हासिल किया। –

+1

मुझे एक ही समस्या थी। मेरा मानना ​​है कि मेरा मुद्दा यह था कि मैं अंदरूनी हैंडलर से सर्वर। शटडाउन() को कॉल करने का प्रयास कर रहा था और उस अनुक्रम का परिणाम डेडलॉक में हुआ क्योंकि मुझे संदेह है कि सर्वर शटलडाउन() कॉल से लौटने से पहले हैंडलर को पूरा करने की प्रतीक्षा कर रहा है। इसका नकारात्मक पक्ष यह है कि मुझे एक डरावनी दिखने वाला अपवाद मिलता है जो स्टडआउट पर मुद्रित होता है जिसे मैं किसी भी तरह दबा देना चाहता हूं। –

+0

मैंने कोशिश की है लेकिन यह अपवाद फेंकता है। हाल के संस्करण में शटडाउन() फ़ंक्शन निर्यात किया गया है। – Feru

10

यह करने के लिए एक और तरीका है, http://docs.python.org/2/library/basehttpserver.html#more-examples के आधार पर उपयोग कर सकते हैं, यह है: serve_forever() के बजाय,, जब तक कि एक की स्थिति उत्पन्न होने की सेवा सर्वर के साथ रखने के प्रत्येक अनुरोध से पहले और बाद में स्थिति की जांच करना। उदाहरण के लिए:

import CGIHTTPServer 
import BaseHTTPServer 

KEEP_RUNNING = True 

def keep_running(): 
    return KEEP_RUNNING 

class Handler(CGIHTTPServer.CGIHTTPRequestHandler): 
    cgi_directories = ["/cgi-bin"] 

httpd = BaseHTTPServer.HTTPServer(("", 8000), Handler) 

while keep_running(): 
    httpd.handle_request() 
+0

यहां और अन्य सभी हैक्स देखने के बाद, यह एक दुर्लभ उत्तर है जो केवल आधिकारिक रूप से प्रलेखित व्यवहार पर निर्भर करता है, इसलिए इसे तोपैनिक माना जाता है। ऊपर वोट किया है! – RayLuo

9

अजगर 2.7 में, बंद बुला() काम करता है लेकिन केवल तभी जब आप, serve_forever के माध्यम से सेवा कर रहे हैं, क्योंकि यह async चयन करें और एक मतदान पाश उपयोग करता है। Handle_request() के साथ अपना खुद का लूप चलाना विडंबनात्मक रूप से इस कार्यक्षमता को छोड़ देता है क्योंकि यह एक गूंगा अवरोधक कॉल का तात्पर्य है।

SocketServer.py के BaseServer से:

def serve_forever(self, poll_interval=0.5): 
    """Handle one request at a time until shutdown. 

    Polls for shutdown every poll_interval seconds. Ignores 
    self.timeout. If you need to do periodic tasks, do them in 
    another thread. 
    """ 
    self.__is_shut_down.clear() 
    try: 
     while not self.__shutdown_request: 
      # XXX: Consider using another file descriptor or 
      # connecting to the socket to wake this up instead of 
      # polling. Polling reduces our responsiveness to a 
      # shutdown request and wastes cpu at all other times. 
      r, w, e = select.select([self], [], [], poll_interval) 
      if self in r: 
       self._handle_request_noblock() 
    finally: 
     self.__shutdown_request = False 
     self.__is_shut_down.set() 

यहाँ एक और धागे से एक अवरुद्ध बंद कर रही है, एक घटना का उपयोग कर पूरा करने के लिए प्रतीक्षा करने के लिए के लिए मेरे कोड का हिस्सा:

class MockWebServerFixture(object): 
    def start_webserver(self): 
     """ 
     start the web server on a new thread 
     """ 
     self._webserver_died = threading.Event() 
     self._webserver_thread = threading.Thread(
       target=self._run_webserver_thread) 
     self._webserver_thread.start() 

    def _run_webserver_thread(self): 
     self.webserver.serve_forever() 
     self._webserver_died.set() 

    def _kill_webserver(self): 
     if not self._webserver_thread: 
      return 

     self.webserver.shutdown() 

     # wait for thread to die for a bit, then give up raising an exception. 
     if not self._webserver_died.wait(5): 
      raise ValueError("couldn't kill webserver") 
+0

यह सही जवाब है! यह मेरे लिए हल हो गया है और यह किसी अन्य चीज की तुलना में आसान है! धन्यवाद! – Elric

0

मैं सब से ऊपर की कोशिश की संभावित समाधान और "कभी-कभी" समस्या होने के साथ समाप्त हो गया - किसी भी तरह से यह वास्तव में ऐसा नहीं करता था - इसलिए मैंने एक गंदा समाधान तैयार किया जो मेरे लिए हर समय काम करता था:

सब से ऊपर विफल रहता है, तो जानवर बल कुछ इस तरह का उपयोग कर अपने धागा मारने:

import subprocess 
cmdkill = "kill $(ps aux|grep '<name of your thread> true'|grep -v 'grep'|awk '{print $2}') 2> /dev/null" 
subprocess.Popen(cmdkill, stdout=subprocess.PIPE, shell=True) 
+1

'server.socket.close()' हमेशा काम करता प्रतीत होता है: –

5

घटना-छोरों SIGTERM पर समाप्त होता है, Ctrl +सी या जब shutdown() कहा जाता है।

server_close() सुन सॉकेट बंद करने के लिए server_forever() ही बुलाया जाना चाहिए।

import http.server 

class StoppableHTTPServer(http.server.HTTPServer): 
    def run(self): 
     try: 
      self.serve_forever() 
     except KeyboardInterrupt: 
      pass 
     finally: 
      # Clean-up server (close socket, etc.) 
      self.server_close() 

सरल सर्वर उपयोगकर्ता कार्रवाई के साथ stoppable (SIGTERM, Ctrl +सी, ...):

server = StoppableHTTPServer(("127.0.0.1", 8080), 
          http.server.BaseHTTPRequestHandler) 
server.run() 

सर्वर एक धागा में चल रहे:

import threading 

server = StoppableHTTPServer(("127.0.0.1", 8080), 
          http.server.BaseHTTPRequestHandler) 

# Start processing requests 
thread = threading.Thread(None, server.run) 
thread.start() 

# ... do things ... 

# Shutdown server 
server.shutdown() 
thread.join() 
संबंधित मुद्दे