# 11.15 `SocketServer` -- ネットワークサーバ構築のための フレームワーク

`SocketServer` モジュールはネットワークサーバを実装するタスクを 単純化します。

このモジュールには 4 つのサーバクラスがあります: `TCPServer` は、クライアントとサーバ間に継続的なデータ流路を提供 する、インターネット TCP プロトコルを使います。 `UDPServer` は、順序通りに到着しなかったり、転送中に喪失して しまってもかまわない情報の断続的なパケットである、データグラムを使います。 `UnixStreamServer` および `UnixDatagramServer` クラスも 同様ですが、Unix ドメインソケットを使います; 従って非 Unix プラットフォームでは利用できません。ネットワークプログラミングに ついての詳細は、W. Richard Steven 著 UNIX Network Programming や、 Ralph Davis 著 Win32 Network Programming のような 書籍を参照してください。

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

サーバの作成にはいくつかのステップがあります。最初に、 `BaseRequestHandler` クラスをサブクラス化して 要求処理クラス (request hander class) を生成し、その `handle()` メソッドを上書きしなければなりません; このメソッドで入力される 要求を処理します。次に、サーバクラスのうち一つをインスタンス化して、 サーバのアドレスと要求処理クラスを渡さなければなりません。最後に、 サーバオブジェクトの `handle_request()` または `serve_forever()` メソッドを呼び出して、単一または多数の 要求を処理します。

`ThreadingMixIn` から継承してスレッドを利用した接続を行う場合、 突発的な通信切断時の処理を明示的に指定する必要があります。 `ThreadingMixIn` クラスには daemon_threads 属性があり、 サーバがスレッドの終了を待ち合わせるかどうかを指定する事ができます。 スレッドが独自の処理を行う場合は、このフラグを明示的に指定します。 デフォルトは`False`で、Pythonは`ThreadingMixIn`クラス が起動した全てのスレッドが終了するまで実行し続けます。

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

`fileno`( | )

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

`handle_request`( | )

  単一の要求を処理します。この関数は以下のメソッド: `get_request()`、 `verify_request()`、および `process_request()` を順番に呼び出します。 ハンドラ中でユーザによって提供された `handle()` が例外 を送出した場合、サーバの `handle_error()` メソッドが 呼び出されます。

`serve_forever`( | )

  無限個の要求を処理します。この関数は単に無限ループ内で `handle_request()` を呼び出します。

`address_family`
  サーバのソケットが属しているプロトコルファミリです。 取りえる値は `socket.AF_INET` および `socket.AF_UNIX` です。

`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` です。

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

`finish_request`( | )

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

`get_request`( | )

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

`handle_error`( | request, client_address)

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

`process_request`( | request, client_address)

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

`server_activate`( | )

  サーバのコンストラクタによって呼び出され、サーバを活動状態に します。 このメソッドは上書きできます。

`server_bind`( | )

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

`verify_request`( | request, client_address)

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

要求処理クラスでは、新たな `handle()` メソッドを定義 しなくてはならず、また以下のメソッドのいずれかを上書きすることができます。 各要求ごとに新たなインスタンスが生成されます。

`finish`( | )

  `handle()` メソッドが呼び出された後、何らかの後始末を行うために 呼び出されます。標準の実装では何も行いません。`setup()` または `handle()` が例外を送出した場合には、この関数は呼び出されません。

`handle`( | )

  この関数では、クライアントからの要求を実現するために必要な全ての作業を 行わなければなりません。この作業の上で、いくつかのインスタンス属性を 利用することができます; クライアントからの要求は `self.request` です; クライアントのアドレスは `self.client_address` です; そしてサーバごとの情報にアクセスする場合には、サーバインスタンスを `self.server` で取得できます。

  `self.request` の型はサービスがデータグラム型かストリーム型かで 異なります。ストリーム型では、`self.request` はソケットオブジェクト です; データグラムサービスでは、`self.request` は文字列になります。 しかし、この違いは要求処理配合クラスの`StreamRequestHandler` や `DatagramRequestHandler`を使うことで隠蔽することができます。 これらのクラスでは `setup()` および `finish()` メソッド を上書きしており、`self.rfile` および `self.wfile` 属性を 提供しています。 `self.rfile` および `self.wfile` は、要求データを取得したり クライアントにデータを返すために、それぞれ読み出し、書き込みを行うことが できます。

`setup`( | )

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