## 1 サーバ生成に関するノート

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

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

`UnixDatagramServer` は `UDPServer` から派生していて、 `UnixStreamServer` からではないことに注意してください -- IP と Unix ストリームサーバの唯一の違いはアドレスファミリーで それは両方の Unix サーバクラスで単純に繰り返されています。

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

        class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass

ミクシンクラスは `UDPServer` で定義されるメソッドをオーバライドするために、 先に来なければなりません。様々なメンバ変数を設定することで元になるサーバ機構の 振る舞いを変えられます。

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

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

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

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

スレッドも `fork()` もサポートされない環境で (もしくはサービスにとってそれらがあまりに高価についたり不適切な場合に) 多数の同時要求を捌くもう一つのアプローチは、部分的に処理し終えた要求のテーブルを 自分で管理し、次にどの要求に対処するか (または新しく入ってきた要求を扱うかどうか)を決めるのに `select()` を使う方法です。 これは(もしスレッドやサブプロセスが使えなければ)特にストリームサービスに対して重要で、 そのようなサービスでは各クライアントが潜在的に長く接続し続けます。