Pythonによる基本的なソケットプログラミング

一般に、ネットワークサービスは、従来のクライアント/サーバーモデルに従っています。あるコンピューターがあるサービスを提供するサーバーとして機能し、別のコンピューターがこのサービスを利用するクライアント側を代表します。ネットワーク上で通信するために、ネットワークソケットが使用されます。このソケット通信は、コンピュータの内部でプロセス間通信(IPC)として利用されることもあります。

この記事では、プログラミング言語Pythonを使用して、ネットワークソケットで通信する簡単なクライアント/サーバーアプリケーションの書き方を説明します。簡単のために、この例のサーバーは受信したデータを標準出力に出力するだけです。クライアント/サーバーアプリケーションのアイデアは、気象観測所のセンサーで、時間の経過とともに温度データを収集し、収集したデータをサーバーアプリケーションに送信し、そこでさらにデータを処理することです。

Socketとは?

ネットワークソケットは、ネットワーク上で動作する2つのプログラムまたはプロセス(この例ではクライアントとサーバー)間の双方向通信リンクの終点となるものです。同じコンピューター上でも、ネットワークで接続された異なるシステム上でも可能です。

両者は、ネットワークソケットに書き込んだり、ネットワークソケットから読み出したりすることで通信を行います。現実の技術的には、2人の参加者が電話で通信するのと同じです。ネットワークソケットは、電話回線に対応する番号、または携帯電話の場合は契約書を表しています。

ソケット機能を利用するためには、Pythonのsocketモジュールだけが必要です。以下のコード例では、気象観測所のシミュレーションと時間計算を簡単にするために、Pythonのtimeモジュールもインポートしています。

この場合、クライアントとサーバーは同じコンピュータで実行されます。ソケットはポート番号に対応しており、この例では23456です。必要であれば、1024から65535の間の無制限の番号から別のポート番号を選択することができます。

サーバー

Python の socket モジュールをロードすると、インターネットストリーミング用のソケットが socket.socket クラスを用いて、 socket.AF_INETsocket.SOCK_STREAM という 2 つのパラメータで生成されます。ホスト名、完全修飾ドメイン名、IP アドレスの取得は、それぞれ gethostname(), getfqdn(), gethostbyname() というメソッドによって行われる。次に、bind() メソッドの助けを借りて、ソケットをIPアドレスとポート番号23456にバインドします。

listen()メソッドの助けを借りて、サーバは指定されたポート番号で着信を待ちます。while ループでは、サーバはリクエストが来るのを待ち、accept()メソッドを用いてそれを受け入れる。クライアントから送信されたデータはrecv()` メソッドによって 64 バイトのチャンクとして読み込まれ、単に標準出力に出力される。最後に、クライアントからそれ以上データが送信されない場合、現在の接続は閉じられる。

# load additional Python module
import socket


# create TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)


# retrieve local hostname
local_hostname = socket.gethostname()


# get fully qualified hostname
local_fqdn = socket.getfqdn()


# get the according IP address
ip_address = socket.gethostbyname(local_hostname)


# output hostname, domain name and IP address
print ("working on %s (%s) with %s" % (local_hostname, local_fqdn, ip_address))


# bind the socket to the port 23456
server_address = (ip_address, 23456)
print ('starting up on %s port %s' % server_address)
sock.bind(server_address)


# listen for incoming connections (server mode) with one connection at a time
sock.listen(1)


while True:
    # wait for a connection
    print ('waiting for a connection')
    connection, client_address = sock.accept()


try:
        # show who connected to us
        print ('connection from', client_address)


# receive the data in small chunks and print it
        while True:
            data = connection.recv(64)
            if data:
                # output received data
                print ("Data: %s" % data)
            else:
                # no more data -- quit the loop
                print ("no more data.")
                break
    finally:
        # Clean up the connection
        connection.close()


クライアント

さて、次はクライアント側を見てみましょう。Pythonのコードはソケットを使う以外はほとんどサーバ側と同じです。クライアントは代わりに connect() メソッドを使っています。forループの中で、sendall()メソッドを用いて温度データをサーバに送信します。time.sleep(2) メソッドを呼び出すと、クライアントは次の温度データを送信する前に 2 秒間停止します。すべての温度データがリストから送信された後、最後に close() メソッドを使用して接続が閉じられます。

# load additional Python modules
import socket
import time


# create TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)


# retrieve local hostname
local_hostname = socket.gethostname()


# get fully qualified hostname
local_fqdn = socket.getfqdn()


# get the according IP address
ip_address = socket.gethostbyname(local_hostname)


# bind the socket to the port 23456, and connect
server_address = (ip_address, 23456)
sock.connect(server_address)
print ("connecting to %s (%s) with %s" % (local_hostname, local_fqdn, ip_address))


# define example data to be sent to the server
temperature_data = ["15", "22", "21", "26", "25", "19"]
for entry in temperature_data:
    print ("data: %s" % entry)
    new_data = str("temperature: %s
" % entry).encode("utf-8")
    sock.sendall(new_data)

    # wait for two seconds
    time.sleep(2)


# close connection
sock.close()


サーバーとクライアントの実行

サーバーとクライアントの両方のプログラムを実行するには、2つのターミナルウィンドウを開き、以下のコマンドをターミナルウィンドウごとに1つずつ、以下の順序で実行してください。

$ python3 echo-server.py


$ python3 echo-client.py


以下の2つの図は、サンプルプログラムの対応する出力を示しています。

図1
황황

図 2

まとめ

Pythonでソケットを使ったIPCプログラムを書くのは簡単です。この例は、より複雑な処理を行うために拡張することができます。より詳細な情報や追加メソッドについては、Pythonのソケットプログラミングのリソースを参照してください。

タイトルとURLをコピーしました