7

私は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() 関数は無限ループに陥り、「停止」条件に遭遇したときにのみループから抜け出すはずであるという考えが得られます。私のメインコールは serve_forever() です。SvcStop 関数があります。

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

コマンドラインから「python myservice stop」を実行すると呼び出されるようですが(出力をファイルに生成するデバッグ行をそこに配置できます)、実際にはサービス全体を終了しません-その後の「python myservice start」への呼び出し"エラーが発生します:

サービスの開始エラー: サービスのインスタンスは既に実行されています。

そして、その後の stop の呼び出しは私に与えます:

サービスの停止中にエラーが発生しました: サービスは現在、制御メッセージを受け入れることができません。(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)
4

1 に答える 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)

in SvcStop() は必要ないはずです

于 2008-09-30T19:47:49.903 に答える