Pythonでネットワークプログラミング(1)

UNIXネットワークプログラミング入門

UNIXネットワークプログラミング入門

自分のようなネットワークプログラミング初心者には、この本はとても良い。言語はCだけど。本の中のサンプルコードに、誤りが(ほとんど*1)無いのが素晴らしい。長々とサンプルを入力した挙句、動かなかったということはよくあるが、デバッグできないと学ぶのが嫌になってしまうものだ。本の内容は、ソケットを使ったクライアント・サーバモデルによるネットワークプログラミングの入門。
7章まで読んだ。最後まで読み終わる前に、居ても立ってもいられず、Pythonで同じことをやりたいときには、どのような実装になるのかを調べてみた。
このへんを参考にして。
Recipe 52218: Message Passing With Socket Datagrams
Python Library Reference 17.2.3 Example

チャットプログラムの実装

上記本の中の最初の例として、チャットプログラムが示されている(第2章)。サーバプロセスとクライアントプロセスの間で、メッセージのやり取りを行うプログラム。どんなものかというと、

  • 通信にはコネクション型を用いる。
  • メッセージの入力は交互に行う。
  • 相手のメッセージは自分の画面に表示される。
  • チャットを終了するには、quitと入力する。

これのPython版を作成してみた。

サーバプログラムは以下の通り。

# file name: server.py
import socket

HOST = 'localhost' #サーバプログラムを動作させるホストを入力
PORT = 50007      #接続するポート番号指定
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT)) #サーバのアドレスをソケットに設定
s.listen(1)   #1つの接続要求を待つ
soc, addr = s.accept()  #要求が来るまでブロックする
print 'Conneted by', addr
print 'Go ahead!'  #サーバ側から先に書き込む

while 1:
    data = raw_input('(server) > ') #サーバ側の入力
    soc.send(data)   #ソケットに書き込む
    data = soc.recv(1024) #1024バイトまでのデータを受け取る
    print '(client) >',data
    if data == "quit":   #quitが入力されたら終了
        break
soc.close()

クライアントプログラムは以下の通り。

# file name: client.py
import socket

HOST = 'localhost' #サーバプログラムを動作させるホストを入力
PORT = 50007

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))

print 'Wait!'  #サーバ側の書き込みを待つ

while 1:
    data = s.recv(1024) #データの受信(1024バイトまで)
    print '(server) >', data
    data = raw_input('(client) > ') #クライアント側の入力
    s.send(data)     #ソケットに書き込む
    if data == "quit":  #quitが入力されたら終了
        break
s.close()

プログラムの実行方法

テストのため、localhostで実行してみる。

  • ターミナル画面を2つ開く。
  • 一方の画面(サーバ側画面)で、python server.pyを実行する。画面には何も表示されない。
  • 次に、もう一方の画面(クライアント側画面)で、python client.pyを実行する。このとき、サーバ側の画面に、「Go ahead!」とプロンプトが表示されるので、メッセージを入力する。
  • サーバ側から書きこんだメッセージが、クライアント側画面に表示される。同時にプロンプトも表示され、書き込み準備される。
  • 次に、クライアント側画面からメッセージを入力する。その内容がサーバ側画面に表示される。
  • 以後、交互にメッセージを入力する。
  • 終了は、どちらかの画面で「quit」を入力する。


ちゃんと動作するので、この実装で間違っていないと思われる。

*1:exit();となっているためコンパイルが通らないところがあった。