ホームページ > バックエンド開発 > Python チュートリアル > SocketServer モジュールを使用して Python で基本的なサーバー プログラムを作成するためのチュートリアル

SocketServer モジュールを使用して Python で基本的なサーバー プログラムを作成するためのチュートリアル

WBOY
リリース: 2016-08-04 08:55:43
オリジナル
1550 人が閲覧しました

SocketServer はネットワーク サーバーの作成を簡素化します。これには、TCPServer、UDPServer、UnixStreamServer、UnixDatagramServer の 4 つのクラスがあります。これら 4 つのクラスは同期的に処理され、非同期は ForkingMixIn クラスと ThreadingMixIn クラスを通じてサポートされます。

サーバーを作成する手順。まず、BaseRequestHandler をサブクラス化し、その handle() メソッドをオーバーライドするリクエスト処理クラスを作成する必要があります。次に、サーバーのアドレスとリクエスト ハンドラー クラスを渡して、サーバー クラスをインスタンス化する必要があります。最後に、handle_request() (通常は他のイベント ループを呼び出すか、select() を使用します) またはserve_forever() を呼び出します。

ThreadingMixIn クラスを統合するときに例外シャットダウンを処理する必要があります。 daemon_threads は、サーバーがスレッドの終了を待機するかどうかを示します。スレッドが互いに独立している場合は、デフォルトは False に設定する必要があります。

どのようなネットワーク プロトコルが使用されても、サーバー クラスには同じ外部メソッドとプロパティがあります。

Python3では、このモジュールはsocketserverモジュールです。 Python 2 では、このモジュールは SocketServer モジュールです。したがって、importを使用してインポートする場合は、状況に応じてインポートする必要があります。そうしないとエラーが報告されます。インポートされたコードは次のとおりです:

リーリー

SocketSerror モジュールには、TCP、UDP、UNIX ドメイン ソケット サーバーの実装を簡素化する多くのクラスが含まれています。

1. 処理手順
このモジュールを使用するには、基本クラス BaseRequestHandler を継承するハンドラー クラスを定義する必要があります。 BaseRequestHandler クラスのインスタンス h は次のメソッドを実装できます:
1. h.handle() このメソッドを呼び出して、実際のリクエスト操作を実行します。この関数はパラメータなしで呼び出すことができますが、いくつかのインスタンス変数には有用な値が含まれています。 h.request にはリクエストが含まれ、h.client_address にはクライアント アドレスが含まれ、h.server にはハンドラーを呼び出したインスタンスが含まれます。 TCP などのデータ ストリーミング サービスの場合、h.request 属性はソケット オブジェクトです。データグラム サービスの場合、受信したデータを含むバイト文字列です。
2. h.setup() このメソッドは handle() の前に呼び出されます。デフォルトでは何もしません。サーバーにさらに多くの接続設定 (SSL 接続の確立など) を実装させたい場合は、ここで実行できます。
3. h.finish() handle() の実行後にクリーンアップ操作を実行するには、このメソッドを呼び出します。デフォルトでは何もしません。 setup() メソッドも handle() メソッドも例外を生成しない場合、このメソッドを呼び出す必要はありません。
アプリケーションがストリーム指向の接続 (TCP など) のみを操作できることがわかっている場合は、BaseRequestHandler ではなく StreamRequestHandler を継承する必要があります。 StreamRequestHandler クラスは 2 つの属性を設定します。 h.wfile はクライアントにデータを書き込むファイルのようなオブジェクトであり、h.rfile はクライアントからデータを読み取るファイルのようなオブジェクトです。
パケットを操作し、送信者に応答を継続的に返すハンドラーを作成する場合は、DatagramRequestHandler を継承する必要があります。提供するクラス インターフェイスは StramRequestHandler と同じです。

2. サーバー
ハンドラーを使用するには、サーバー オブジェクトにハンドラーを挿入する必要があります。 4 つの基本的なサーバー クラスが定義されています。
(1) TCPServer(アドレス,ハンドラ)は、IPv4 の TCP プロトコルを使用するサーバーをサポートします。アドレスは (ホスト, ポート) タプルです。 Handler は、BaseRequestHandler クラスまたは StreamRequestHandler クラスのサブクラスのインスタンスです。
(2) UDPServer(address,handler) は、IPv4 の UDP プロトコルを使用するサーバーをサポートします。アドレスとハンドラーは TCPServer と同様です。
(3) UnixStreamServer(address,handler) は、UNIX ドメイン ソケットを使用して、TCPServer から継承されたデータ ストリーム プロトコル指向のサーバーを実装します。
(4) UnixDatagramServer(address,handler) UDPServer から継承した、UNIX ドメイン ソケットを使用してデータグラム プロトコルを実装するサーバー。
4 つのサーバー クラスすべてのインスタンスには、次のメソッドと変数があります:
1. s.socket 受信リクエストに使用されるソケット オブジェクト。
2. s.sever_address リスニングサーバーのアドレス。タプル ("127.0.0.1",80) など
3. s.RequestHandlerClass サーバー コンストラクターに渡され、ユーザーによって提供されるリクエスト ハンドラー クラス。
4. s.serve_forever() は無制限のリクエストを処理します
5. s.shutdown()serve_forever()ループを停止します
6. s.fileno() サーバーソケットの整数のファイル記述子を返します。このメソッドは、select() 関数などのポーリング操作を通じてサーバー インスタンスを効果的に使用します。

三、定义自定义服务器
服务器往往需要特殊的配置来处理不同的网络地址族、超时期、并发和其他功能,可以通过继承上面四个基本服务器类来自行定义。
可以通过混合类获得更多服务器功能,这也是通过进程或线程分支添加并发行的方法。为了实现并发性,定义了以下类:
(1)ForkingMixIn         将UNIX进程分支添加到服务器的混合方法,使用该方法可以让服务器服务多个客户。
(2)ThreadingMixIn    修改服务器的混合类,可以使用线程服务多个客户端。
要向服务器添加这些功能,可以使用多重继承,其中首先列出混了类。
由于并发服务器很常用,为了定义它,SocketServer预定义了以下服务器类:
(1)ForkingUDPServer(address,handler)  
(2)ForkingTCPServer(address,handler)
(3)ThreadingUDPServer(address,handler)
(4)ThreadingTCPServer(address,handler)
上面有点乱,现总结以下:
SocketServer模块中的类主要有以下几个:
1、BaseServer    包含服务器的核心功能与混合类(mix-in)的钩子功能。这个类主要用于派生,不要直接生成这个类的类对象,可以考虑使用TCPServer和UDPServer类。
2、TCPServer    基本的网络同步TCP服务器
3、UDPServer    基本的网络同步UDP服务器
4、ForkingMixIn   实现了核心的进程化功能,用于与服务器类进行混合(mix-in),以提供一些异步特性。不要直接生成这个类的对象。
5、ThreadingMixIn   实现了核心的线程化功能,用于与服务器类进行混合(mix-in),以提供一些异步特性。不要直接生成这个类的对象。
6、ForkingTCPServer     ForkingMixIn与TCPServer的组合
7、ForkingUDPServer    ForkingMixIn与UDPServer的组合
8、BaseRequestHandler
9、StreamRequestHandler    TCP请求处理类的一个实现
10、DataStreamRequestHandler   UDP请求处理类的一个实现
现在繁杂的事务都已经封装到类中了,直接使用类即可。

四、实例
1.使用SocketServer模块编写的TCP服务器端代码:

#! /usr/bin/env python
#coding=utf-8
"""使用SocketServer来实现简单的TCP服务器"""
from SocketServer import (TCPServer,StreamRequestHandler as SRH)
from time import ctime
class MyRequestHandler(SRH):
  def handle(self):
    print "connected from ",self.client_address
    self.wfile.write("[%s] %s" %(ctime(),self.rfile.readline()))
tcpSer=TCPServer(("",10001),MyRequestHandler)
print "waiting for connection"
tcpSer.serve_forever()
相应的TCP客户端代码:
#! /usr/bin/env python
#coding=utf-8
from socket import *
BUFSIZE=1024
#每次都要创建新的连接
while True:
  tcpClient=socket(AF_INET,SOCK_STREAM)
  tcpClient.connect(("localhost",10001))
  data=raw_input(">")
  if not data:
    break
  tcpClient.send("%s\r\n" %data)
  data1=tcpClient.recv(BUFSIZE)
  if not data1:
    break
  print data1.strip()
  tcpClient.close()
ログイン後にコピー

2.异步服务器的实现

ThreadingMixIn的例子:

import socketimport threadingimport SocketServerclass ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):

  def handle(self):
    data = self.request.recv(1024)
    cur_thread = threading.current_thread()
    response = "{}: {}".format(cur_thread.name, data)
    self.request.sendall(response)class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
  passdef client(ip, port, message):
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  sock.connect((ip, port))
  try:
    sock.sendall(message)
    response = sock.recv(1024)
    print "Received: {}".format(response)
  finally:
    sock.close()if __name__ == "__main__":
  # Port 0 means to select an arbitrary unused port
  HOST, PORT = "localhost", 0

  server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
  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
ログイン後にコピー

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート