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

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

```python
# 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)
```
```python
# 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 管理ツール]⇒[サービス]で登録されていることを確認しましょう