📝

PythonでWindows サービス(SocketServer)を作成

2023/04/29に公開

Windows 2019Server(Windows10でも同じ)
Python 3.7.8

Pythonをインストール

python-3.7.8.exeを使用してインストール
今回は諸事情で32bit版をインストールしていますが64bit版でも問題ないはず

ライブラリのインストール

Windowsサービスということで今回はpywin32を使用する

pip install pywin32

※もし上記のコマンドで64bit版のpywin32がインストールされてしまう場合は32bit版の.whlファイルを事前に準備し直接指定してインストールを行いましょう

環境変数

以下の6つの環境変数が設定されていることを確認する

# ユーザ環境変数.path
C:\Users\<ユーザ名>\AppData\Local\Programs\Python\Python37-32\Scripts\
C:\Users\<ユーザ名>\AppData\Local\Programs\Python\Python37-32\
# システム環境変数.path
C:\Users\<ユーザ名>\AppData\Local\Programs\Python\Python37-32\Scripts\
C:\Users\<ユーザ名>\AppData\Local\Programs\Python\Python37-32\
C:\Users\<ユーザ名>\AppData\Local\Programs\Python\Python37-32\Lib\site-packages\pywin32_system32
C:\Users\<ユーザ名>\AppData\Local\Programs\Python\Python37-32\Lib\site-packages\win32

実行ファイル

今回はタイトルにもある通りSocketServerサービスをPythonで実装する
必要なモジュールは以下の2つです

  • service.py
  • server.py
service.py
import os
import win32service
import win32serviceutil
import win32event
import logging
import servicemanager
import socket
import datetime

from socketserver import ThreadingTCPServer
import server

logging.basicConfig(
    filename=ログ出力先,
    level=logging.DEBUG,
    format="%(asctime)s:LINE[%(lineno)s] %(levelname)s %(message)s"
)

class PythonService(win32serviceutil.ServiceFramework):
    _svc_name_ = 'SocketServer Test'
    _svc_display_name_ = 'SocketServer Test'
    _svc_description_ = 'SocketServer Test description'

    def __init__(self, args):
        win32serviceutil.ServiceFramework.__init__(self, args)
        self.stop_event = win32event.CreateEvent(None, 0, 0, None)
        socket.setdefaulttimeout(60)
        self.stop_requested = False

        ipaddr = 'IPアドレス'
        port = ポート番号
        address = (ipaddr, int(port))
        sockserver = ThreadingTCPServer(address, server.EchoHandler)
        self.sockserver = sockserver

    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.stop_event)
        self.stop_requested = True
        self.sockserver.shutdown()

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

    def main(self):
        while True:
            if self.stop_requested:
                break
            try:
                ThreadingTCPServer.allow_reuse_address = True
                self.sockserver.serve_forever()
            except Exception as e:
                logging.error(str(type(e)))
                logging.error(str(e.args))
                logging.error(str(e))

if __name__ == '__main__':
    win32serviceutil.HandleCommandLine(PythonService)
server.py
from socketserver import BaseRequestHandler
import logging
import datetime
import os

logging.basicConfig(
    filename=ログ出力先,
    level=logging.DEBUG,
    format="%(asctime)s:LINE[%(lineno)s] %(levelname)s %(message)s"
)

class EchoHandler(BaseRequestHandler):
    def handle(self):
        try:
            message = self.request.recv(1024)
            logging.info(message)
            self.request.sendall(message)

        except Exception as e:
            logging.error(str(type(e)))
            logging.error(str(e.args))
            logging.error(str(e))

注意点

  • 上記の2ファイルは同じフォルダ内に配置しましょう
  • serve_forever()したsocketserverはサービス停止時に必ずshutdownさせる処理を書きましょう。これをしないとサービスを停止できず、削除も出来なくなります

サービス登録

配置したpythonファイルのフォルダに移動し以下のコマンドを実行します

# サービス登録
python service.py install
# サービス開始
python service.py start

[スタート]⇒[Windows 管理ツール]⇒[サービス]で登録されていることを確認しましょう

GitHubで編集を提案

Discussion