我有一个用Python编写的小型Web服务器应用程序,它从数据库系统获取一些数据,并以XMLforms返回给用户。 这部分工作正常 – 我可以从命令行运行Python Web服务器应用程序,我可以让客户端连接到它并获取数据。 目前,要运行Web服务器,必须以pipe理员用户身份login到我们的服务器,并且必须手动启动Web服务器。 我想让Web服务器自动作为服务启动,并在后台运行。
使用ActiveState的站点和StackOverflow的代码,我对如何创build一个服务有一个很好的想法,我想我已经有了一点sorting – 我可以安装并启动我的Web服务器作为Windows服务。 然而,我不能弄清楚如何再次停止服务。 我的networking服务器是从一个BaseHTTPServer创build的:
server = BaseHTTPServer.HTTPServer(('', 8081), SIMSAPIServerHandler) server.serve_forever()
serve_forever()调用很自然地使Web服务器处于一个无限循环,并等待HTTP连接(或者ctrl-break按键,对服务不起作用)。 我从上面的例子代码中得到了这个想法,你的main()函数应该是在一个无限循环中,当它出现在一个“停止”条件时,它只能被打破。 我的主要调用serve_forever()。 我有一个SvcStopfunction:
def SvcStop(self): self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) exit(0)
当我从命令行执行“python myservice stop”(我可以在那里放置一个debugging行来产生输出到一个文件),但是并没有真正退出整个服务时,似乎被调用 – 随后调用“python myservice start “给我一个错误:
启动服务时出错:服务的一个实例已经在运行。
和随后的电话停止给我:
停止服务时出错:此时服务无法接受控制消息。 (1061)
我想我需要一些替代serve_forever(serve_until_stop_received,或其他),或者我需要一些修改SvcStop的方式,所以它停止整个服务。
这是一个完整的列表(我已经修剪包括/评论,以节省空间):
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)
这就是我所做的:
我不是直接实例化BaseHTTPserver.HTTPserver类,而是从它发布一个新的后代,发布一个“停止”方法:
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
然后,在你已经有的方法SvcStop中,我调用该方法来打破serve_forever()循环:
def SvcStop(self): self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) self.httpd.stop()
(self.httpd是实现Web服务器的AppHTTPserver()的实例)
如果在后台线程上正确使用setDaemon(),并正确中断服务中的所有循环,那么该指令
exit(0)
在SvcStop()应该没有必要