2019/08/17

PythonでSocketIO(クライアント編)

背景


PythonでSocketIO通信を行う必要があったため、今後の開発の効率化のためにSocketIO通信を行うクラスのテンプレートを作成する。

記事の目的


PythonでSocketIOクライアントを作成する

python-socketio


python-socketioを使用したSocketIOクライアントを作成する

選定理由

python-socketioの選定理由は、下記の通りである。

導入方法

python-socketioの導入手順は、下記の通りである。
  1. pipを利用して必要なライブラリをインストールする
    1. $ pip install requests python-socketio

テンプレート

python-socketioの使用テンプレートは、下記の通りである。
  1. # socketioライブラリのインポート
  2. import socketio
  3. # ログ出力用ライブラリのインポート
  4. from logging import getLogger, StreamHandler, DEBUG, INFO, ERROR
  5. # 時間関係ライブラリのインポート
  6. import time
  7. # 終了シグナルをキャッチするライブラリのインポート
  8. import signal
  9. # マルチスレッドライブラリのインポート
  10. import threading
  11. # ロガーのインスタンス作成
  12. logger = getLogger(__name__)
  13. stream_handler = StreamHandler()
  14. # ログレベルを設定
  15. log_level = INFO
  16. logger.setLevel(log_level)
  17. stream_handler.setLevel(log_level)
  18. # ロガーにハンドラーをセット
  19. logger.addHandler(stream_handler)
  20. # SocketIOのテンプレート
  21. class SocketIOClient:
  22. # namespaceの設定用クラス
  23. class NamespaceClass(socketio.ClientNamespace):
  24. def on_connect(self):
  25. pass
  26. def on_disconnect(self):
  27. pass
  28. def on_message(self, data):
  29. pass
  30. def on_server_to_client(self, data):
  31. pass
  32. # 接続時に呼ばれるイベント
  33. def on_connect(self):
  34. logger.info('Connected to server (%s:%d, namespace="%s", query="%s")',\
  35. self.ip_,self.port_,self.namespace_,self.query_)
  36. self.is_connect_ = True
  37. # 切断時に呼ばれるイベント
  38. def on_disconnect(self):
  39. logger.info('Disconnected from server (%s:%d, namespace="%s", query="%s")',\
  40. self.ip_,self.port_,self.namespace_,self.query_)
  41. self.is_connect_ = False
  42. def on_message(self, data):
  43. logger.info('Received message %s', str(data))
  44. # サーバーからイベント名「server_to_client」でデータがemitされた時に呼ばれる
  45. def on_server_to_client(self, data):
  46. logger.info('Received message %s', str(data))
  47. # Namespaceクラス内の各イベントをオーバーライド
  48. def overload_event(self):
  49. self.Namespace.on_connect = self.on_connect
  50. self.Namespace.on_disconnect = self.on_disconnect
  51. self.Namespace.on_message = self.on_message
  52. self.Namespace.on_server_to_client = self.on_server_to_client
  53. # 初期化
  54. def __init__(self,ip,port,namespace,query):
  55. self.ip_ = ip
  56. self.port_ = port
  57. self.namespace_ = namespace
  58. self.query_ = query
  59. self.is_connect_ = False
  60. self.sio_ = socketio.Client()
  61. self.Namespace = self.NamespaceClass(self.namespace_)
  62. self.overload_event()
  63. self.sio_.register_namespace(self.Namespace)
  64. # 接続確認
  65. def isConnect(self):
  66. return self.is_connect_
  67. # 接続
  68. def connect(self):
  69. # 接続先のURLとqueryの設定
  70. url = 'ws://'+self.ip_+':'+str(self.port_)+'?query='+self.query_
  71. logger.info('Try to connect to server(%s:%d, namespace="%s", query="%s")',\
  72. self.ip_,self.port_,self.namespace_,self.query_)
  73. try:
  74. self.sio_.connect(url, namespaces=self.namespace_)
  75. except:
  76. logger.error('Cannot connect to server(%s:%d, namespace="%s", query="%s")',\
  77. self.ip_,self.port_,self.namespace_,self.query_)
  78. else:
  79. if not self.is_connect_:
  80. logger.error('Namespace may be invalid.(namespace="%s")',\
  81. self.namespace_)
  82. # 切断
  83. def disconnect(self):
  84. try:
  85. self.sio_.disconnect()
  86. except:
  87. logger.error('Cannot disconnect from server(%s:%d, namespace="%s", query="%s")',\
  88. self.ip_,self.port_,self.namespace_,self.query_)
  89. else:
  90. self.is_connect_ = False
  91. # 再接続
  92. def reconnect(self):
  93. self.disconnect()
  94. time.sleep(5)
  95. self.connect()
  96. # クライアントからデータ送信(send)する
  97. def sendData(self, data):
  98. try:
  99. self.sio_.send(data, namespace=self.namespace_)
  100. except:
  101. logger.error('Has not connected to server(%s:%d, namespace="%s", query="%s")',\
  102. self.ip_,self.port_,self.namespace_,self.query_)
  103. else:
  104. logger.info('Send message %s (namespace="%s")', str(data), self.namespace_)
  105. # 独自定義のイベント名「client_to_server」で、クライアントからデータ送信(emit)する
  106. def emitData(self, data):
  107. try:
  108. self.sio_.emit('client_to_server', data, namespace=self.namespace_)
  109. except:
  110. logger.error('Has not connected to server(%s:%d, namespace="%s", query="%s")',\
  111. self.ip_,self.port_,self.namespace_,self.query_)
  112. else:
  113. logger.info('Emit message %s (namespace="%s")', \
  114. str(data), self.namespace_)
  115. # メインの処理
  116. def run(self):
  117. while True:
  118. self.connect()
  119. time.sleep(1)
  120. if self.is_connect_:
  121. break
  122. p = threading.Thread(target=self.sio_.wait)
  123. p.setDaemon(True)
  124. p.start()
  125. if __name__ == '__main__':
  126. # Ctrl + C (SIGINT) で終了
  127. signal.signal(signal.SIGINT, signal.SIG_DFL)
  128. # SocketIO Client インスタンスを生成
  129. sio_client = SocketIOClient('localhost', 10000, '/test', 'secret')
  130. # SocketIO Client インスタンスを実行
  131. sio_client.run()
  132. # データを送信
  133. for i in range(10):
  134. sio_client.sendData({'test_data': 'send_from_client'})
  135. sio_client.emitData({'test_data': 'emit_from_client'})
  136. time.sleep(1)
  137. # 切断
  138. sio_client.disconnect()
  139. logger.info('Finish')
  140. # 終了
  141. exit()

備考

  • namespaceは、必ず「/」(スラッシュ)から始まる必要がある
  • 上記テンプレートは、サーバーと通信テストができる

まとめ


  • Python-SocketIOを利用したクライアントモジュールを作成した

参考文献



変更履歴


  1. 2019/08/17: 新規作成

0 件のコメント:

コメントを投稿

MQTTの導入

背景 IoTデバイスの接続環境構築のため、MQTT(mosquitto)の導入を行った。 記事の目的 MQTT(mosquitto)をUbuntuに導入する mosquitto ここではmosquittoについて記載する。 MQTT MQTT(Message Qu...