Python & Raspberry Pi 開発ブログ ☆彡

PythonとRaspberry Piの基本的な使い方をわかりやすく解説。初心者、入門者必見!!

Python SocketIO通信の仕方:クライアント編

今回は、PythonでSocket.IOモジュールを使って、クライアントとサーバー間でコミュニケーションする方法を紹介したいと思います。webページの値を更新したり、webページから入力された文字等を取得できたりしますので、とても重宝します。それでは、クラアント側のプログラムについて説明してきます。

Socket.IOモジュールのインストール

下記コマンドでSocket.IOモジュールをインストールします。

$ pip install "python-socketio[client]"

asyncioでの使い方は今回は紹介しませんが、コードの一部を置き換えるだけで使えるようになります。興味がある方は、下記のSocket.IOモジュールのドキュメントを参考にして、試してみてください。

Socket.IOの基本

ここにSocket.IOモジュールのドキュメントがあります。参考にしてください。

python-socketio.readthedocs.io

サーバーとクライアントのコミュニケーションの仕方

データをサーバー⇒クライアント、またはサーバーからクライアントに送るときは、emitという関数を使います。emitの第1引数と受信側の関数名を一致させて使う必要があります。

# 送信側;サーバーorクライアントでemit関数を使用してデータを送信する
emit('response', data) 

# 受信側:サーバーorクライアントの'response’という関数名の関数が実行されます。
def response(data):
    print(data)
※emit関数(送信側)でイベント(受信側)を発生させることができる。emitの第1引数の名前のイベントが受信側で発生するので、上記コードのresponseという名前を一致させる必要がある。

イベントハンドラの登録

Socket.IOは双方向のイベントベースの通信プロトコルです。何かやりたい場合は、イベントハンドラを登録する必要があります。デコレータ(@sio.event)を使う方法とNamespacesクラスを使用してon_関数名で使う方法があります。

@sio.event # デコレータを使用する場合
def connect(sid, environ):
    # 処理
    
class MyCustomNamespace(socketio.Namespace): # Namespacesクラスを使用する場合
    def on_connect(self, sid, environ):
     # 処理

名前空間(Namespace)

サーバーとクライアントで同じ名前空間(Namespace)を使わないと接続ができません。逆に接続を個別に行いたいときは名前空間を分けて設定します。下記のchatやtestの部分で名前空間を設定します。

http://192.168.0.1:3000/
http://192.168.0.1:3000/chat
http://192.168.0.1:3000/test

Socket.IOモジュールでは、デコレータを使う方法をNamespacesクラスを使う方法をがあります。コードの1部分になりますので、ざっとイメージを掴むだけで問題ありません。

@sio.event(namespace='/chat')
def connect(sid, environ):
    # 処理
    
class MyCustomNamespace(socketio.Namespace): # Namespacesクラスを使用する場合
    def on_connect(self, sid, environ):
      # 処理  
sio.register_namespace(MyCustomNamespace('/chat'))

また、名前空間の中をさらにroomという機能で個別に管理することもできます。

それでは全体のコードを見ていきましょう。

Socket.IOクライアントのPythonコード

コード内にコメントも記載しましたので、参考にしてください。testという名前空間で、バックグラウンドタスクでemit関数でサーバーにメッセージを送信しています。また、サーバーからのレスポンスはon_response関数で受信するコードになっています。

・start_background_task(関数、引数) ⇒ 第一引数の関数がバックグラウンドタスクとして動作します。引数も渡すことができます。

import socketio
import time
from datetime import datetime


class MyCustomNamespace(socketio.ClientNamespace): # 名前空間を設定するクラス
    def on_connect(self):
        print('[{}] connect'.format(datetime.now().strftime('%Y-%m-%d %H:%M:%S')))

    def on_disconnect(self):
        print('[{}] disconnect'.format(datetime.now().strftime('%Y-%m-%d %H:%M:%S')))

    def on_response(self, msg):
        print('[{}] response : {}'.format(datetime.now().strftime('%Y-%m-%d %H:%M:%S') , msg))


class SocketIOClient:
    
    def __init__(self, host, path):
        self.host = host 
        self.path = path
        self.sio = socketio.Client()
    
    def connect(self):

        self.sio.register_namespace(MyCustomNamespace(self.path)) # 名前空間を設定
        self.sio.connect(self.host) # サーバーに接続
        self.sio.start_background_task(self.my_background_task, 123) # バックグラウンドタスクの登録 (123は引数の書き方の参考のため、処理には使っていない)
        self.sio.wait() # イベントが待ち
        
    def my_background_task(self, my_argument): # ここにバックグランド処理のコードを書く
        while True:
            input_data = input("send data:") # ターミナルから入力された文字を取得
            self.sio.emit('broadcast_message', input_data, namespace = self.path) # ターミナルで入力された文字をサーバーに送信
            self.sio.sleep(1)

if __name__ == '__main__':
    sio_client = SocketIOClient('http://192.168.0.10:3000', '/test') # SocketIOClientクラスをインスタンス化
    sio_client.connect()

これでSocketIOのクライアントは完成です。サーバーを起動後、このクライアントもpythonで実行してください。ターミナルに"send data:"という文字が表示されるはずです。何か文字や数字を入力して、Enterキーを押してください。サーバー側に入力した文字が送られ、同じ文字が返ってきます。これで、クライアント側の説明は終了です。

ラズパイ ソフトウェアに戻る
トップページに戻る