SocketServerモジュールを使ったサーバプログラムの実装
Pythonでのネットワークプログラミングの方法をいろいろと検討している。今回は、「SocketServer」と「asyncore」というキーワードに関して調べてみた。
- 参考サイト:
Python2.6 doc (SocketServer)
Python2.6 doc (asyncore)
SocketServer - ネットワークサービスを作成する
asyncore - 非同期I/Oハンドラ
一通りドキュメントを読んでみたが、すぐに全部を理解できるほど勉強が進んでいない。実用的なネットワークサービスプログラムを作成するとき、有用なモジュールであることは理解できた。今後も読み返して考える。
今回の検討項目
SocketServerモジュールで、早速、サーバプログラムを実装してみる。このモジュールを使えば、接続が複数ある場合にも処理が簡単になる(らしい)。その場合、ThreadingMixInクラスかForkingMixInクラスを利用する(らしい)。そこまで高度なことは今はやらずに、簡単なプログラムで試しにSocketServerを使ってみる。
コマンドpsを実行するプログラム
クライアント側からコマンドを送って、サーバ側でそのコマンドを実行し、結果をクライアントへ送信するプログラムを作ってみる。今の場合、サーバで実行させるコマンドはpsとする。SocketServerモジュールを使わない場合のサーバプログラムは以下の通り。bindとか、acceptとか、whileループを使っている。
# sv01.py import socket, sys, os def main(): port = 9999 ls = socket.socket(socket.AF_INET, socket.SOCK_STREAM); ls.bind(('', port)) while 1: ls.listen(1) (conn, addr) = ls.accept() print 'client is at', addr #クライアント側ホスト名 rc = conn.recv(2) #コマンドpsを受信 ppn = os.popen(rc) #コマンドの実行 rl = ppn.read() #コマンドの実行結果を読み込み conn.send(rl) conn.close() #コマンドの実行結果を送信 if __name__ == '__main__': main()
一方で、クライアントプログラムは以下の通り。
# cl01.py import socket, sys def main(): host = 'localhost' #接続先ホスト名 port = 9999 #ポート番号 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((host, port)) cmd = 'ps' s.send(cmd) #コマンドpsを送信 data = s.recv(1024) #1024バイト受信 print data #受信データを表示 if __name__ == '__main__': main()
プログラムの実行方法は次のようにする。
- ターミナル画面を2つ開く。
- 一方の画面(サーバ側画面)で、「python sv01.py」を実行する。この時点では何も起こらない。
- もう一方の画面(クライアント側画面)で、「python cl01.py」を実行する。すると、サーバへ送られたpsコマンドがサーバ側で実行され実行結果がクライアント側画面に表示される。
- サーバ側のプログラムは実行したままの状態で、クライアント側では
繰り返し「python cl01.py」を実行できる。下図に実行例を示す。
サーバプログラムでSocketServerモジュールを使う
上記のサーバプログラムsv01.pyにおいて、SocketServerモジュールを使うように修正する。修正後のサーバプログラムは以下の通り。
# sv02.py import SocketServer import os class MyTCPHandler(SocketServer.BaseRequestHandler): def handle(self): print ">connect from:", self.client_address cmd = self.request.recv(2) rl = os.popen(cmd) data = rl.read() self.request.send(data) if __name__ == '__main__': host, port = '', 9999 server = SocketServer.TCPServer((host, port), MyTCPHandler) # server = SocketServer.ThreadingTCPServer((host, port), MyTCPHandler) server.serve_forever()
プログラムの実行方法や動作は、修正前と変わらない。
プログラムが単純すぎて、SocketServerモジュールの有難味がわからない...。