WindowsでPython Webサーバーをサービスとして実行する
質問
Pythonで作成した小さなWebサーバーアプリケーションがあり、データベースシステムからデータを取得してXMLとしてユーザーに返します。その部分は正常に機能します。コマンドラインからPython Webサーバーアプリケーションを実行し、クライアントに接続してデータを取得させることができます。現時点では、Webサーバーを実行するには、管理者ユーザーとしてサーバーにログインし、Webサーバーを手動で起動する必要があります。サービスとしてシステムを起動すると、Webサーバーが自動的に起動し、バックグラウンドで実行されるようにします。
ActiveState のサイトおよびStackOverflow 、私は行く方法についてかなり良いアイデアを持っていますサービスを作成することについて、そして私はそのビットをソートしていると思う-私はWindowsサービスとして私のサーバーをインストールして起動することができます。ただし、サービスを再度停止する方法はわかりません。 WebサーバーはBaseHTTPServerから作成されます。
server = BaseHTTPServer.HTTPServer(('', 8081), SIMSAPIServerHandler)
server.serve_forever()
serve_forever()呼び出しは、当然のことながら、Webサーバーを無限ループに入れてHTTP接続(またはサービスには役に立たないctrl-breakキー押下)を待機させます。上記のサンプルコードから、main()関数は無限ループにあり、「stop」を通過したときにのみ抜け出すことになっているという考えが得られます。調子。私の主な呼び出しは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)
解決
これは私がしていることです:
クラス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()では必要ありません