在Windows中将Python Web服务器作为服务运行

8
我编写了一个小型的Python Web服务器应用程序,从数据库系统中获取数据并将其作为XML返回给用户。这部分工作很好-我可以从命令行运行Python Web服务器应用程序,并且客户端可以连接并获取数据。目前,要运行Web服务器,我必须以管理员用户身份登录到我们的服务器,并手动启动Web服务器。我希望Web服务器能够在系统启动时自动作为服务启动并在后台运行。
使用ActiveState网站和StackOverflow的代码,我对如何创建服务有了一个很好的想法,我认为我已经解决了这个问题-我可以安装和启动我的Web服务器作为Windows服务。然而,我无法弄清楚如何停止该服务。我的Web服务器是从BaseHTTPServer创建的。
server = BaseHTTPServer.HTTPServer(('', 8081), SIMSAPIServerHandler)
server.serve_forever()

serve_forever()方法自然而然地让Web服务器进入无限循环状态并等待HTTP连接(或者通过ctrl-break键进行中断,对于服务来说没有用)。我从上面的示例代码中得到的想法是你的main()函数应该进入一个无限循环状态,并且只有在遇到“停止”条件时才能跳出循环。我的main调用serve_forever()方法。我有一个SvcStop函数:

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

当我从命令行执行“python myservice stop”时,似乎会调用它(我可以在其中放置一个产生输出到文件的调试行),但实际上并没有退出整个服务——对“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)
1个回答

4
这是我的工作内容:
我不直接实例化BaseHTTPServer.HTTPServer类,而是编写一个它的子类,并添加了一个名为“stop”的方法。
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()中不应该是必需的


你能帮忙回答这个问题吗?它与这个上下文有关:https://dev59.com/D37aa4cB1Zd3GeqPoUs_ - Deepak Ingole

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接