"socketserver" --- ネットワークサーバーのフレームワーク
*******************************************************

**ソースコード:** Lib/socketserver.py

======================================================================

"socketserver" モジュールを使うと、ネットワークサーバを簡単に作成でき
ます。

利用可能な環境: not WASI.

このモジュールは WebAssembly では動作しないか、利用不可です。詳しくは
、WebAssembly プラットフォーム を見てください。

基本的な具象サーバクラスが4つあります:

class socketserver.TCPServer(server_address, RequestHandlerClass, bind_and_activate=True)

   クライアントとサーバの間で連続したデータストリームを提供する、イン
   ターネットの TCP プロトコルを使います。 *bind_and_activate* が真の
   場合、コンストラクターは "server_bind()" と "server_activate()" を
   自動的に呼び出そうとします。 ほかの引数は基底クラス "BaseServer" に
   渡されます。

   バージョン 3.15 で変更: "socketserver.TCPServer" のデフォルトのキュ
   ーサイズが "socket.SOMAXCONN" になりました。

class socketserver.UDPServer(server_address, RequestHandlerClass, bind_and_activate=True)

   データグラムを使います。 データグラムは個々に独立した情報のパケット
   で、順序が入れ替わって到着したり、転送中に失われたりすることがあり
   ます。 引数は "TCPServer" と同じです。

class socketserver.UnixStreamServer(server_address, RequestHandlerClass, bind_and_activate=True)
class socketserver.UnixDatagramServer(server_address, RequestHandlerClass, bind_and_activate=True)

   あまり使われないこれらのクラスは TCP や UDP のクラスと似ていますが
   、Unix ドメインソケットを使います。 Unix 以外のプラットフォームでは
   利用できません。 引数は "TCPServer" と同じです。

これらの 4 つのクラスは要求を *同期的に (synchronously)* 処理します;
各要求は次の要求を開始する前に完結していなければなりません。同期的な処
理は、サーバで大量の計算を必要とする、あるいはクライアントが処理するに
は時間がかかりすぎるような大量のデータを返す、といった理由によってリク
エストに長い時間がかかる状況には向いていません。こうした状況の解決方法
は別のプロセスを生成するか、個々の要求を扱うスレッドを生成することです
;  "ForkingMixIn" および "ThreadingMixIn" 配合クラス (mix-in classes)
を使えば、非同期的な動作をサポートできます。

サーバの作成にはいくつかのステップが必要です。最初に、
"BaseRequestHandler" クラスをサブクラス化して要求処理クラス (request
hander class) を生成し、その "handle()" メソッドをオーバーライドしなけ
ればなりません; このメソッドは入力される要求を処理します。次に、サーバ
クラスのうち一つを、サーバのアドレスと要求処理クラスを渡してインスタン
ス化しなければなりません。サーバを "with" 文中で使うことが推奨されます
。そして、"handle_request()" または "serve_forever()" メソッドを呼び出
して、一つのまたは多数の要求を処理します。最後に、("with" 文を使ってい
なかったなら) "server_close()" を呼び出してソケットを閉じます。

"ThreadingMixIn" から継承してスレッドを利用した接続を行う場合、突然終
了する場合のスレッドの動作を明示的に指定する必要があります。
"ThreadingMixIn" クラスには *daemon_threads* 属性があり、サーバがスレ
ッドの終了を待ち合わせるかどうかを指定する事ができます。 スレッドの終
了を待たずに終了させたい場合は、このフラグを明示的に設定してください。
デフォルトは "False" で、Pythonは "ThreadingMixIn" クラスが起動した全
てのスレッドが終了するまで実行し続けます。

サーバクラス群は使用するネットワークプロトコルに関わらず、同じ外部メソ
ッドおよび属性を持ちます。


サーバ生成に関するノート
========================

継承図にある五つのクラスのうち四つは四種類の同期サーバを表わしています
:

   +------------+
   | BaseServer |
   +------------+
         |
         v
   +-----------+        +------------------+
   | TCPServer |------->| UnixStreamServer |
   +-----------+        +------------------+
         |
         v
   +-----------+        +--------------------+
   | UDPServer |------->| UnixDatagramServer |
   +-----------+        +--------------------+

"UnixDatagramServer" は "UDPServer" から派生していて、
"UnixStreamServer" からではないことに注意してください --- IP と Unix
サーバの唯一の違いはアドレスファミリーです。

class socketserver.ForkingMixIn
class socketserver.ThreadingMixIn

   それぞれのタイプのサーバのフォークしたりスレッド実行したりするバー
   ジョンはそれらのミクシン(mix-in)クラスを使って作ることができます。
   たとえば、"ThreadingUDPServer" は以下のようにして作られます:

      class ThreadingUDPServer(ThreadingMixIn, UDPServer):
          pass

   ミクシンクラスは "UDPServer" で定義されるメソッドをオーバライドする
   ために、最初に来ます。様々な属性を設定することで元になるサーバ機構
   の振る舞いを変えられます。

   "ForkingMixIn" と以下で説明する Forking クラスは、"fork()" をサポー
   トする POSIX プラットフォームでのみ利用できます。

   block_on_close

      "ForkingMixIn.server_close" は、"block_on_close" 属性が "False"
      でない限り、すべての子プロセスの終了を待ちます。

      "ThreadingMixIn.server_close" は、"block_on_close" 属性が
      "False" でない限り、すべての非デーモンスレッドの終了を待ちます。

   max_children

      "ForkingMixIn" で、同時に要求を処理する子プロセスの最大数を指定
      します。 上限に達すると、新たな要求は子プロセスが 1 つ終了するま
      で待機します。

   daemon_threads

      "ThreadingMixIn" でスレッドの終了を待たないようにするには、
      "ThreadingMixIn.daemon_threads" を "True" に設定してデーモンスレ
      ッドを使ってください。

   バージョン 3.7 で変更: "ForkingMixIn.server_close" と
   "ThreadingMixIn.server_close" は、すべての子プロセスと非デーモンス
   レッドが終了するまで待つようになりました。 3.7 より前の動作を選べる
   よう、クラス属性 "ForkingMixIn.block_on_close" が追加されました。

class socketserver.ForkingTCPServer
class socketserver.ForkingUDPServer
class socketserver.ThreadingTCPServer
class socketserver.ThreadingUDPServer
class socketserver.ForkingUnixStreamServer
class socketserver.ForkingUnixDatagramServer
class socketserver.ThreadingUnixStreamServer
class socketserver.ThreadingUnixDatagramServer

   これらのクラスは、ミクシンクラスを使ってあらかじめ定義されています
   。

Added in version 3.12: "ForkingUnixStreamServer" クラスと
"ForkingUnixDatagramServer" クラスが追加されました。

サービスの実装には、 "BaseRequestHandler" からクラスを派生させてその
"handle()" メソッドを再定義しなければなりません。このようにすれば、サ
ーバクラスと要求処理クラスを結合して様々なバージョンのサービスを実行す
ることができます。要求処理クラスはデータグラムサービスかストリームサー
ビスかで異なることでしょう。この違いは処理サブクラス
"StreamRequestHandler" または "DatagramRequestHandler" を使うという形
で隠蔽できます。

もちろん、まだ頭を使わなければなりません! たとえば、サービスがリクエス
トによっては書き換えられるようなメモリ上の状態を使うならば、フォークす
るサーバを使うのは馬鹿げています。というのも子プロセスでの書き換えは親
プロセスで保存されている初期状態にも親プロセスから分配される各子プロセ
スの状態にも届かないからです。この場合、スレッド実行するサーバを使うこ
とはできますが、共有データの一貫性を保つためにロックを使わなければなら
なくなるでしょう。

一方、全てのデータが外部に(たとえばファイルシステムに)保存される HTTP
サーバを作っているのだとすると、同期クラスではどうしても一つの要求が処
理されている間サービスが「耳の聞こえない」状態を呈することになります
--- この状態はもしクライアントが要求した全てのデータをゆっくり受け取る
ととても長い時間続きかねません。こういう場合にはサーバをスレッド実行し
たりフォークすることが適切です。

ある場合には、要求の一部を同期的に処理する一方で、要求データに依って子
プロセスをフォークして処理を終了させる、といった方法も適当かもしれませ
ん。こうした処理方法は同期サーバを使って要求処理クラスの "handle()" メ
ソッドの中で自分でフォークするようにして実装することができます。

スレッドも "fork()" もサポートされていない環境 (あるいはコストが高すぎ
たり、そのサービスに適さなかったりする場合) で複数の要求を同時に処理す
る方法もあります。 処理途中の要求を明示的に表で管理し、"selectors" を
使って次に処理する要求 (または新しく届いた要求を処理するかどうか) を決
める方法です。 これは、各クライアントが長時間接続し続ける可能性のある
ストリームサービスで、スレッドやサブプロセスを使えない場合に特に重要で
す。


Serverオブジェクト
==================

class socketserver.BaseServer(server_address, RequestHandlerClass)

   このモジュールのすべてのサーバオブジェクトのスーパークラスです。 以
   下のインターフェースを定義しますが、ほとんどのメソッドは実装せず、
   サブクラスで実装します。 2 つの引数は、それぞれ "server_address" 属
   性と "RequestHandlerClass" 属性に格納されます。

   fileno()

      サーバが要求待ちを行っているソケットのファイル記述子を整数で返し
      ます。この関数は一般的に、同じプロセス中の複数のサーバを監視でき
      るようにするために、 "selectors" に渡されます。

   handle_request()

      単一の要求を処理します。この関数は以下のメソッド:
      "get_request()" 、 "verify_request()" 、および
      "process_request()" を順番に呼び出します。ハンドラ中でユーザによ
      って提供された "handle()" が例外を送出した場合、サーバの
      "handle_error()" メソッドが呼び出されます。 "timeout" 秒以内にリ
      クエストが来なかった場合、 "handle_timeout()" が呼ばれて、
      "handle_request()" が終了します。

   serve_forever(poll_interval=0.5)

      "shutdown()" が明示的に要求されるまで、要求を処理します。
      *poll_interval* 秒ごとに終了要求の有無を調べます。 "timeout" 属
      性は無視します。 また、"service_actions()" も呼び出します。 サブ
      クラスやミクシンは、このメソッドを使ってサービス固有の処理を行え
      ます。 例えば "ForkingMixIn" は "service_actions()" を使ってゾン
      ビ状態の子プロセスを回収します。

      バージョン 3.3 で変更: "serve_forever" メソッドに
      "service_actions" の呼び出しが追加されました。

   service_actions()

      "serve_forever()" のループ内で呼び出されます。 サブクラスやミク
      シンクラスでオーバーライドして、クリーンアップなどのサービス固有
      の処理を行えます。

      Added in version 3.3.

   shutdown()

      "serve_forever()" のループに停止を指示し、停止するまで待ちます。
      "shutdown()" は、"serve_forever()" が別のスレッドで実行されてい
      る間に呼び出す必要があります。 そうしないとデッドロックします。

   server_close()

      サーバをクリーンアップします。上書き出来ます。

   address_family

      サーバのソケットが属するプロトコルファミリーです。 よく使われる
      ものには "socket.AF_INET"、"socket.AF_INET6"、"socket.AF_UNIX"
      があります。 IPv6 サーバのクラスが必要な場合は、このモジュールの
      TCP または UDP サーバクラスを継承し、クラス属性を
      "address_family = AF_INET6" と設定してください。

   RequestHandlerClass

      ユーザが提供する要求処理クラスです; 要求ごとにこのクラスのインス
      タンスが生成されます。

   server_address

      サーバが要求待ちを行うアドレスです。アドレスの形式はプロトコルフ
      ァミリによって異なります。詳細は "socket" モジュールを参照してく
      ださい。インターネットプロトコルでは、この値は例えば
      "('127.0.0.1', 80)" のようにアドレスを与える文字列と整数のポート
      番号を含むタプルです。

   socket

      サーバが入力の要求待ちを行うためのソケットオブジェクトです。

   サーバクラスは以下のクラス変数をサポートします:

   allow_reuse_address

      サーバがアドレスの再使用を許すかどうかを示す値です。この値は標準
      で "False" で、サブクラスで再使用ポリシを変更するために設定する
      ことができます。

   request_queue_size

      要求待ち行列 (queue) のサイズです。単一の要求を処理するのに長時
      間かかる場合には、サーバが処理中に届いた要求は最大
      "request_queue_size" 個まで待ち行列に置かれます。待ち行列が一杯
      になると、それ以降のクライアントからの要求は "接続拒否
      (Connection denied)" エラーになります。標準の値は通常 5 ですが、
      この値はサブクラスで上書きすることができます。

   socket_type

      サーバが使うソケットの型です; 一般的な2つの値は、
      "socket.SOCK_STREAM" と "socket.SOCK_DGRAM" です。

   timeout

      タイムアウト時間(秒)、もしくは、タイムアウトを望まない場合に
      "None" 。 "handle_request()" がこの時間内にリクエストを受信しな
      い場合、 "handle_timeout()" メソッドが呼ばれます。

   "TCPServer" のような基底クラスのサブクラスで上書きできるサーバメソ
   ッドは多数あります; これらのメソッドはサーバオブジェクトの外部のユ
   ーザにとっては役にたたないものです。

   finish_request(request, client_address)

      "RequestHandlerClass" をインスタンス化し、 "handle()" メソッドを
      呼び出して、実際に要求を処理します。

   get_request()

      ソケットから要求を受理して、クライアントとの通信に使われる *新し
      い* ソケットオブジェクト、およびクライアントのアドレスからなる、
      2 要素のタプルを返します。

   handle_error(request, client_address)

      この関数は "RequestHandlerClass" インスタンスの "handle()" メソ
      ッドが例外を送出した際に呼び出されます。標準の動作では標準エラー
      出力へトレースバックを出力し、後続する要求を継続して処理します。

      バージョン 3.6 で変更: "Exception" クラスから派生した例外に対し
      てのみ呼び出すようになりました。

   handle_timeout()

      この関数は "timeout" 属性が "None" 以外に設定されて、リクエスト
      がないままタイムアウト秒数が過ぎたときに呼ばれます。 fork型サー
      バーでのデフォルトの動作は、終了した子プロセスの情報を集めるよう
      になっています。スレッド型サーバーではこのメソッドは何もしません
      。

   process_request(request, client_address)

      "finish_request()" を呼び出して、 "RequestHandlerClass" のインス
      タンスを生成します。必要なら、この関数から新たなプロセスかスレッ
      ドを生成して要求を処理することができます; その処理は
      "ForkingMixIn" または "ThreadingMixIn"  クラスが行います。

   server_activate()

      サーバを有効にするために、サーバのコンストラクターから呼び出され
      ます。 TCP サーバのデフォルトの動作は、サーバのソケットに対して
      "listen()" を呼び出すだけです。 オーバーライドできます。

   server_bind()

      サーバのコンストラクタによって呼び出され、適切なアドレスにソケッ
      トをバインドします。このメソッドは上書きできます。

   verify_request(request, client_address)

      ブール値を返さなければなりません; 値が "True" の場合には要求が処
      理され、 "False" の場合には要求は拒否されます。サーバへのアクセ
      ス制御を実装するためにこの関数を上書きすることができます。標準の
      実装では常に "True" を返します。

   バージョン 3.6 で変更: *context manager* プロトコルのサポートが追加
   されました。コンテキストマネージャを終了することは、
   "server_close()" を呼ぶことと同一です。


要求処理オブジェクト
====================

class socketserver.BaseRequestHandler

   すべての要求処理オブジェクトのスーパークラスです。 以下のインターフ
   ェースを定義します。 具象の要求処理サブクラスは "handle()" メソッド
   を新たに定義する必要があり、ほかのメソッドもオーバーライドできます
   。 要求ごとにサブクラスの新しいインスタンスを作成します。

   setup()

      "handle()"   メソッドより前に呼び出され、何らかの必要な初期化処
      理を行います。標準の実装では何も行いません。

   handle()

      この関数は、要求に応えるために必要なすべての処理を行わなければな
      りません。 デフォルトの実装は何もしません。 いくつかのインスタン
      ス属性を利用できます。 要求は "request"、クライアントのアドレス
      は "client_address" に格納されています。 サーバ固有の情報が必要
      な場合は、"server" からサーバのインスタンスにアクセスできます。

      "request" の型は、データグラムサービスとストリームサービスで異な
      ります。 ストリームサービスでは "request" はソケットオブジェクト
      です。 データグラムサービスでは "request" はバイト列とソケットの
      ペアです。

   finish()

      "handle()"   メソッドより後に呼び出され、何らかの必要なクリーン
      アップ処理を行います。標準の実装では何も行いません。 "setup()"
      メソッドが例外を送出した場合、このメソッドは呼び出されません。

   request

      The *new* "socket.socket" object to be used to communicate with
      the client.

   client_address

      "BaseServer.get_request()" が返したクライアントのアドレスです。

   server

      要求の処理に使う "BaseServer" オブジェクトです。

class socketserver.StreamRequestHandler
class socketserver.DatagramRequestHandler

   これらの "BaseRequestHandler" のサブクラスは、"setup()" メソッドと
   "finish()" メソッドをオーバーライドし、"rfile" 属性と "wfile" 属性
   を提供します。

   rfile

      受信した要求を読み取るためのファイルオブジェクトです。
      "io.BufferedIOBase" の読み取り用インターフェースをサポートします
      。

   wfile

      応答を書き込むためのファイルオブジェクトです。
      "io.BufferedIOBase" の書き込み用インターフェースをサポートします
      。

   バージョン 3.6 で変更: "wfile" も "io.BufferedIOBase" の書き込み用
   インターフェースをサポートするようになりました。


使用例
======


"socketserver.TCPServer" の例
-----------------------------

サーバサイドの例です:

   import socketserver

   class MyTCPHandler(socketserver.BaseRequestHandler):
       """
       このサーバの要求処理クラス。

       サーバへの接続ごとに 1 回インスタンス化される。
       handle() メソッドをオーバーライドして、
       クライアントとの通信を実装する必要がある。
       """

       def handle(self):
           # self.request はクライアントと接続された TCP ソケット
           pieces = [b'']
           total = 0
           while b'\n' not in pieces[-1] and total < 10_000:
               pieces.append(self.request.recv(2000))
               total += len(pieces[-1])
           self.data = b''.join(pieces)
           print(f"Received from {self.client_address[0]}:")
           print(self.data.decode("utf-8"))
           # 同じデータを大文字に変えて送り返す
           self.request.sendall(self.data.upper())
           # このメソッドから戻るとソケットは閉じられる。

   if __name__ == "__main__":
       HOST, PORT = "localhost", 9999

       # localhost のポート 9999 にバインドしてサーバを作成する
       with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server:
           # サーバを起動する。
           # Ctrl-C でプログラムを中断するまで動き続ける。
           server.serve_forever()

別の、ストリーム(標準のファイル型のインターフェースを利用して通信をシ
ンプルにしたファイルライクオブジェクト)を使うリクエストハンドラクラス
の例です:

   class MyTCPHandler(socketserver.StreamRequestHandler):

       def handle(self):
           # self.rfile はハンドラーが作成したファイル類似オブジェクト。
           # recv() を直接呼ぶ代わりに、例えば readline() を使える。
           # 送信側による悪用を防ぐため、10000 バイトに制限する。
           self.data = self.rfile.readline(10000).rstrip()
           print(f"{self.client_address[0]} wrote:")
           print(self.data.decode("utf-8"))
           # 同様に、self.wfile はクライアントへの書き込みに使う
           # ファイル類似オブジェクト。
           self.wfile.write(self.data.upper())

2 番目のハンドラーでは、"readline()" が改行文字に到達するまで "recv()"
を繰り返し呼び出す点が異なります。 最初のハンドラーでは、改行に到達す
るまでデータを蓄積するために、自分で "recv()" のループを書く必要があり
ました。 ループを使わずに "recv()" を 1 回だけ呼び出していたら、その時
点までにクライアントから受信できたデータだけが返されていたでしょう。
TCP はストリームに基づいています。 データは送信した順に届きますが、ク
ライアントでの "send()" や "sendall()" の呼び出し回数と、それを受信す
るためにサーバで必要な "recv()" の呼び出し回数には対応関係がありません
。

クライアントサイドの例:

   import socket
   import sys

   HOST, PORT = "localhost", 9999
   data = " ".join(sys.argv[1:])

   # ソケットを作成する (SOCK_STREAM は TCP ソケットを表す)
   with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
       # サーバに接続してデータを送信する
       sock.connect((HOST, PORT))
       sock.sendall(bytes(data, "utf-8"))
       sock.sendall(b"\n")

       # サーバからデータを受信して終了する
       received = str(sock.recv(1024), "utf-8")

   print("Sent:    ", data)
   print("Received:", received)

この例の出力は次のようになります:

サーバー:

   $ python TCPServer.py
   127.0.0.1 wrote:
   b'hello world with TCP'
   127.0.0.1 wrote:
   b'python is nice'

クライアント:

   $ python TCPClient.py hello world with TCP
   Sent:     hello world with TCP
   Received: HELLO WORLD WITH TCP
   $ python TCPClient.py python is nice
   Sent:     python is nice
   Received: PYTHON IS NICE


"socketserver.UDPServer" の例
-----------------------------

サーバサイドの例です:

   import socketserver

   class MyUDPHandler(socketserver.BaseRequestHandler):
       """
       This class works similar to the TCP handler class, except that
       self.request consists of a pair of data and client socket, and since
       there is no connection the client address must be given explicitly
       when sending data back via sendto().
       """

       def handle(self):
           data = self.request[0].strip()
           socket = self.request[1]
           print(f"{self.client_address[0]} wrote:")
           print(data)
           socket.sendto(data.upper(), self.client_address)

   if __name__ == "__main__":
       HOST, PORT = "localhost", 9999
       with socketserver.UDPServer((HOST, PORT), MyUDPHandler) as server:
           server.serve_forever()

クライアントサイドの例:

   import socket
   import sys

   HOST, PORT = "localhost", 9999
   data = " ".join(sys.argv[1:])

   # SOCK_DGRAM は UDP ソケットに使うソケットの種類
   sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

   # UDP には接続がないため、connect() は呼び出さない。
   # 代わりに sendto() で受信側へ直接データを送信する。
   sock.sendto(bytes(data + "\n", "utf-8"), (HOST, PORT))
   received = str(sock.recv(1024), "utf-8")

   print("Sent:    ", data)
   print("Received:", received)

この例の出力は、TCPサーバーの例と全く同じようになります。


非同期処理の Mix-in
-------------------

複数の接続を非同期に処理するハンドラを作るには、 "ThreadingMixIn" か
"ForkingMixIn" クラスを利用します。

"ThreadingMixIn" クラスの利用例:

   import socket
   import threading
   import socketserver

   class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):

       def handle(self):
           data = str(self.request.recv(1024), 'ascii')
           cur_thread = threading.current_thread()
           response = bytes("{}: {}".format(cur_thread.name, data), 'ascii')
           self.request.sendall(response)

   class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
       pass

   def client(ip, port, message):
       with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
           sock.connect((ip, port))
           sock.sendall(bytes(message, 'ascii'))
           response = str(sock.recv(1024), 'ascii')
           print("Received: {}".format(response))

   if __name__ == "__main__":
       # ポート 0 は、未使用の任意のポートを選ぶことを意味する
       HOST, PORT = "localhost", 0

       server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
       with server:
           ip, port = server.server_address

           # サーバを実行するスレッドを開始する。
           # このスレッドが要求ごとにさらに 1 つスレッドを開始する。
           server_thread = threading.Thread(target=server.serve_forever)
           # メインスレッドの終了時にサーバスレッドも終了させる
           server_thread.daemon = True
           server_thread.start()
           print("Server loop running in thread:", server_thread.name)

           client(ip, port, "Hello World 1")
           client(ip, port, "Hello World 2")
           client(ip, port, "Hello World 3")

           server.shutdown()

この例の出力は次のようになります:

   $ python ThreadedTCPServer.py
   Server loop running in thread: Thread-1
   Received: Thread-2: Hello World 1
   Received: Thread-3: Hello World 2
   Received: Thread-4: Hello World 3

"ForkingMixIn" クラスは同じように利用することができます。この場合、サ
ーバーはリクエスト毎に新しいプロセスを作成します。"fork()" をサポート
する POSIX プラットフォームでのみ利用可能です。
