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

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

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

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

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

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

   This uses the Internet TCP protocol, which provides for continuous
   streams of data between the client and server. If
   *bind_and_activate* is true, the constructor automatically attempts
   to invoke "server_bind()" and "server_activate()".  The other
   parameters are passed to the "BaseServer" base class.

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

   This uses datagrams, which are discrete packets of information that
   may arrive out of order or be lost while in transit.  The
   parameters are the same as for "TCPServer".

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

   These more infrequently used classes are similar to the TCP and UDP
   classes, but use Unix domain sockets; they're not available on non-
   Unix platforms.  The parameters are the same as for "TCPServer".

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

Creating a server requires several steps.  First, you must create a
request handler class by subclassing the "BaseRequestHandler" class
and overriding its "handle()" method; this method will process
incoming requests.  Second, you must instantiate one of the server
classes, passing it the server's address and the request handler
class. It is recommended to use the server in a "with" statement. Then
call the "handle_request()" or "serve_forever()" method of the server
object to process one or many requests.  Finally, call
"server_close()" to close the socket (unless you used a "with"
statement).

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

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


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

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

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

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

class socketserver.ForkingMixIn
class socketserver.ThreadingMixIn

   Forking and threading versions of each type of server can be
   created using these mix-in classes.  For instance,
   "ThreadingUDPServer" is created as follows:

      class ThreadingUDPServer(ThreadingMixIn, UDPServer):
          pass

   The mix-in class comes first, since it overrides a method defined
   in "UDPServer".  Setting the various attributes also changes the
   behavior of the underlying server mechanism.

   "ForkingMixIn" and the Forking classes mentioned below are only
   available on POSIX platforms that support "fork()".

class socketserver.ForkingTCPServer
class socketserver.ForkingUDPServer
class socketserver.ThreadingTCPServer
class socketserver.ThreadingUDPServer

   These classes are pre-defined using the mix-in classes.

To implement a service, you must derive a class from
"BaseRequestHandler" and redefine its "handle()" method. You can then
run various versions of the service by combining one of the server
classes with your request handler class.  The request handler class
must be different for datagram or stream services.  This can be hidden
by using the handler subclasses "StreamRequestHandler" or
"DatagramRequestHandler".

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

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

In some cases, it may be appropriate to process part of a request
synchronously, but to finish processing in a forked child depending on
the request data.  This can be implemented by using a synchronous
server and doing an explicit fork in the request handler class
"handle()" method.

Another approach to handling multiple simultaneous requests in an
environment that supports neither threads nor "fork()" (or where these
are too expensive or inappropriate for the service) is to maintain an
explicit table of partially finished requests and to use "selectors"
to decide which request to work on next (or whether to handle a new
incoming request).  This is particularly important for stream services
where each client can potentially be connected for a long time (if
threads or subprocesses cannot be used).  See "asyncore" for another
way to manage this.


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

class socketserver.BaseServer(server_address, RequestHandlerClass)

   This is the superclass of all Server objects in the module.  It
   defines the interface, given below, but does not implement most of
   the methods, which is done in subclasses.  The two parameters are
   stored in the respective "server_address" and "RequestHandlerClass"
   attributes.

   fileno()

      Return an integer file descriptor for the socket on which the
      server is listening.  This function is most commonly passed to
      "selectors", to allow monitoring multiple servers in the same
      process.

   handle_request()

      Process a single request.  This function calls the following
      methods in order: "get_request()", "verify_request()", and
      "process_request()".  If the user-provided "handle()" method of
      the handler class raises an exception, the server's
      "handle_error()" method will be called.  If no request is
      received within "timeout" seconds, "handle_timeout()" will be
      called and "handle_request()" will return.

   serve_forever(poll_interval=0.5)

      Handle requests until an explicit "shutdown()" request.  Poll
      for shutdown every *poll_interval* seconds. Ignores the
      "timeout" attribute.  It also calls "service_actions()", which
      may be used by a subclass or mixin to provide actions specific
      to a given service.  For example, the "ForkingMixIn" class uses
      "service_actions()" to clean up zombie child processes.

      バージョン 3.3 で変更: Added "service_actions" call to the
      "serve_forever" method.

   service_actions()

      This is called in the "serve_forever()" loop. This method can be
      overridden by subclasses or mixin classes to perform actions
      specific to a given service, such as cleanup actions.

      バージョン 3.3 で追加.

   shutdown()

      "serve_forever()" ループに停止するように指示し、停止されるまで待
      ちます。

   server_close()

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

   address_family

      サーバのソケットが属しているプロトコルファミリです。一般的な値は
      "socket.AF_INET" および "socket.AF_UNIX" です。

   RequestHandlerClass

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

   server_address

      The address on which the server is listening.  The format of
      addresses varies depending on the protocol family; see the
      documentation for the "socket" module for details.  For Internet
      protocols, this is a tuple containing a string giving the
      address, and an integer port number: "('127.0.0.1', 80)", for
      example.

   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)

      Actually processes the request by instantiating
      "RequestHandlerClass" and calling its "handle()" method.

   get_request()

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

   handle_error(request, client_address)

      This function is called if the "handle()" method of a
      "RequestHandlerClass" instance raises an exception.  The default
      action is to print the traceback to standard error and continue
      handling further requests.

      バージョン 3.6 で変更: Now only called for exceptions derived
      from the "Exception" class.

   handle_timeout()

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

   process_request(request, client_address)

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

   server_activate()

      Called by the server's constructor to activate the server.  The
      default behavior for a TCP server just invokes "listen()" on the
      server's socket.  May be overridden.

   server_bind()

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

   verify_request(request, client_address)

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

   バージョン 3.6 で変更: Support for the *context manager* protocol
   was added.  Exiting the context manager is equivalent to calling
   "server_close()".


21.21.3. Request Handler Objects
================================

class socketserver.BaseRequestHandler

   This is the superclass of all request handler objects.  It defines
   the interface, given below.  A concrete request handler subclass
   must define a new "handle()" method, and can override any of the
   other methods.  A new instance of the subclass is created for each
   request.

   setup()

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

   handle()

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

      The type of "self.request" is different for datagram or stream
      services.  For stream services, "self.request" is a socket
      object; for datagram services, "self.request" is a pair of
      string and socket.

   finish()

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

class socketserver.StreamRequestHandler
class socketserver.DatagramRequestHandler

   These "BaseRequestHandler" subclasses override the "setup()" and
   "finish()" methods, and provide "self.rfile" and "self.wfile"
   attributes. The "self.rfile" and "self.wfile" attributes can be
   read or written, respectively, to get the request data or return
   data to the client.

   The "rfile" attributes of both classes support the
   "io.BufferedIOBase" readable interface, and
   "DatagramRequestHandler.wfile" supports the "io.BufferedIOBase"
   writable interface.

   バージョン 3.6 で変更: "StreamRequestHandler.wfile" also supports
   the "io.BufferedIOBase" writable interface.


21.21.4. 使用例
===============


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

サーバサイドの例です:

   import socketserver

   class MyTCPHandler(socketserver.BaseRequestHandler):
       """
       The request handler class for our server.

       It is instantiated once per connection to the server, and must
       override the handle() method to implement communication to the
       client.
       """

       def handle(self):
           # self.request is the TCP socket connected to the client
           self.data = self.request.recv(1024).strip()
           print("{} wrote:".format(self.client_address[0]))
           print(self.data)
           # just send back the same data, but upper-cased
           self.request.sendall(self.data.upper())

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

       # Create the server, binding to localhost on port 9999
       with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server:
           # Activate the server; this will keep running until you
           # interrupt the program with Ctrl-C
           server.serve_forever()

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

   class MyTCPHandler(socketserver.StreamRequestHandler):

       def handle(self):
           # self.rfile is a file-like object created by the handler;
           # we can now use e.g. readline() instead of raw recv() calls
           self.data = self.rfile.readline().strip()
           print("{} wrote:".format(self.client_address[0]))
           print(self.data)
           # Likewise, self.wfile is a file-like object used to write back
           # to the client
           self.wfile.write(self.data.upper())

先ほどとの違いは、"readline()" の呼び出しが、改行を受け取るまで
"recv()" を複数回呼び出すことです。1回の "recv()" の呼び出しは、クライ
アントから1回の "sendall()" 呼び出しで送信された分しか受け取りません。

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

   import socket
   import sys

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

   # Create a socket (SOCK_STREAM means a TCP socket)
   with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
       # Connect to server and send data
       sock.connect((HOST, PORT))
       sock.sendall(bytes(data + "\n", "utf-8"))

       # Receive data from the server and shut down
       received = str(sock.recv(1024), "utf-8")

   print("Sent:     {}".format(data))
   print("Received: {}".format(received))

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

Server:

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

Client:

   $ 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


21.21.4.2. "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("{} wrote:".format(self.client_address[0]))
           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 is the socket type to use for UDP sockets
   sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

   # As you can see, there is no connect() call; UDP has no connections.
   # Instead, data is directly sent to the recipient via sendto().
   sock.sendto(bytes(data + "\n", "utf-8"), (HOST, PORT))
   received = str(sock.recv(1024), "utf-8")

   print("Sent:     {}".format(data))
   print("Received: {}".format(received))

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


21.21.4.3. 非同期処理の 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__":
       # Port 0 means to select an arbitrary unused port
       HOST, PORT = "localhost", 0

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

           # Start a thread with the server -- that thread will then start one
           # more thread for each request
           server_thread = threading.Thread(target=server.serve_forever)
           # Exit the server thread when the main thread terminates
           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

The "ForkingMixIn" class is used in the same way, except that the
server will spawn a new process for each request. Available only on
POSIX platforms that support "fork()".
