2008-09-30 6 views
6

Laufen habe ich eine Anwendung kleiner Webserver ich in Python geschrieben habe, dass einige Daten aus einem Datenbanksystem geht und bekommt und gibt es als XML an den Benutzer. Dieser Teil funktioniert gut - ich kann die Python-Webserver-Anwendung über die Befehlszeile ausführen und ich kann Clients damit verbinden und Daten zurück erhalten. Im Moment muss ich, um den Webserver laufen zu lassen, bei unserem Server als Administrator angemeldet sein und den Webserver manuell starten. Ich möchte den Webserver beim Systemstart automatisch als Dienst starten lassen und im Hintergrund laufen lassen.ein Python-Web-Server als Dienst in Windows

Mit Code von ActiveState ‚s Website und StackOverflow, ich habe eine ziemlich gute Vorstellung davon, wie, geht über einen Service, und ich glaube, ich habe das Stück sortiert - ich kann meinen Web-Server als einen installieren und starten Windows-Dienst Ich kann jedoch nicht herausfinden, wie ich den Dienst wieder stoppen kann. Mein Web-Server wird von einem BaseHTTPServer erstellt:

server = BaseHTTPServer.HTTPServer(('', 8081), SIMSAPIServerHandler) 
server.serve_forever() 

Der serve_forever() -Aufruf, natürlich genug, macht die Web-Server sitzt in einer Endlosschleife und warten Sie auf HTTP-Verbindungen (oder ctrl-Pause keypress, nicht nützlich für Ein Dienst). Ich bekomme die Idee aus dem obigen Beispielcode, dass deine main() -Funktion in einer Endlosschleife sitzen soll und nur dann ausbrechen soll, wenn sie über eine "Stop" -Bedingung kommt. Meine wichtigsten Anrufe serve_forever(). Ich habe eine SvcStop Funktion:

def SvcStop(self): 
    self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) 
    exit(0) 

Welche genannt scheint zu werden, wenn ich „Python myservice stop“ von der Kommandozeile zu tun (ich eine Debug-Zeile, dort setzen kann, dass die Ausgabe in eine Datei erzeugt), aber nicht tatsächlich den gesamten Service verlassen - nachfolgende Aufrufe von „python myservice start“ gibt mir eine Fehlermeldung:

Error starting service: An instance of the service is already running.

und nachfolgende Aufrufe zu stoppen, gibt mir:

Error stopping service: The service cannot accept control messages at this time. (1061)

ich glaube, ich brauche entweder eine re Platzierung für serve_forever (serve_until_stop_received oder was auch immer) oder ich brauche eine Möglichkeit, SvcStop so zu modifizieren, dass es den gesamten Service stoppt.

Hier ist eine vollständige Liste (ich habe getrimmten includes/Kommentare Platz zu sparen):

class SIMSAPIServerHandler(BaseHTTPServer.BaseHTTPRequestHandler): 
    def do_GET(self): 
     try: 
      reportTuple = self.path.partition("/") 
      if len(reportTuple) < 3: 
       return 
      if reportTuple[2] == "": 
       return 
      os.system("C:\\Programs\\SIMSAPI\\runCommandReporter.bat " + reportTuple[2]) 
      f = open("C:\\Programs\\SIMSAPI\\out.xml", "rb") 
      self.send_response(200) 
      self.send_header('Content-type', "application/xml") 
      self.end_headers() 
      self.wfile.write(f.read()) 
      f.close() 
      # The output from CommandReporter is simply dumped to out.xml, which we read, write to the user, then remove. 
      os.unlink("C:\\Programs\\SIMSAPI\\out.xml") 
      return 
     except IOError: 
      self.send_error(404,'File Not Found: %s' % self.path) 



class SIMSAPI(win32serviceutil.ServiceFramework): 
    _svc_name_ = "SIMSAPI" 
    _svc_display_name_ = "A simple web server" 
    _svc_description_ = "Serves XML data produced by SIMS CommandReporter" 

    def __init__(self, args): 
     win32serviceutil.ServiceFramework.__init__(self, args) 
     self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)   

    def SvcStop(self): 
      self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) 
      exit(0) 

    def SvcDoRun(self): 
     import servicemanager 
     servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,servicemanager.PYS_SERVICE_STARTED,(self._svc_name_, '')) 

     self.timeout = 3000 

     while 1: 
      server = BaseHTTPServer.HTTPServer(('', 8081), SIMSAPIServerHandler) 
      server.serve_forever() 

def ctrlHandler(ctrlType): 
    return True 

if __name__ == '__main__': 
    win32api.SetConsoleCtrlHandler(ctrlHandler, True) 
    win32serviceutil.HandleCommandLine(SIMSAPI) 

Antwort

3

Das ist, was ich tue:

Statt direkt die Klasse BaseHTTPServer.HTTPServer von Instancing, ich schreibe ein neuer Nachkomme von ihm, die ein „Stop“ Methode veröffentlicht:

class AppHTTPServer (SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer): 
    def serve_forever(self): 
     self.stop_serving = False 
     while not self.stop_serving: 
      self.handle_request() 

    def stop (self): 
     self.stop_serving = True 

Und dann wird bei dem Verfahren SvcStop, die Sie bereits haben, nenne ich diese Methode brechen die serve_forever() Loop:

def SvcStop(self): 
    self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) 
    self.httpd.stop() 

(self.httpd ist die Instanz von AppHTTPServer(), die den Web-Server implementiert)

Wenn Sie setDaemon() korrekt auf den Hintergrund-Threads, und Interrupt korrekt alle Schleifen in der Service, dann der Befehl

exit(0) 

in SvcStop() sollte nicht notwendig sein

+0

können Sie mit Frage in diesem Zusammenhang helfen [hier] (http://stackoverflow.com/questions/228 14933/make-server-und-konsole-daemon-as-service-in-windows) –