ESP32同士でsocket通信をしたい
実装がかなり大変だったため,備忘録として.
はじめに:ソケット通信って?
他の方で非常に良い記事がありましたのでそちらを参照ください.
https://qiita.com/megadreams14/items/32a3eed4661e55419e1c
プログラム:何はともあれまずはソースコード
環境:
>>> os.uname()
(sysname='esp32', nodename='esp32', release='1.17.0', version='v1.17 on 2021-09-02', machine='ESP32 module with ESP32')
TCPサーバ
import socket #モジュールのインポート
port = 80 #ポート指定
listenSocket = None #初期化
ip = wifi.ifconfig()[0] #自分のipアドレスを取得
listenSocket = socket.socket() #socketを作成
listenSocket.bind((ip, port)) # ソケットを特定のIPアドレスとポートに紐付け
listenSocket.listen(5) # 接続の待受を開始
listenSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) #指定されたソケットオプションの値を設定
while True:
print("accepting.....")
conn, addr = listenSocket.accept() #接続を受信
print(addr, "connected") #接続した相手のipアドレスを表示 (xxx.xxx.xxx.xxx connected)
while True:
data = conn.recv(1024) #一度に受け取るデータのサイズを指定
if(len(data) == 0):
print("close socket")
conn.close() #接続を切断
break
print(data)
TCPクライアント
import socket
s = socket.socket() #ソケットの作成
host = '192.168.0.18' #接続先のipアドレス
port = 80 #ポート指定
s.connect(socket.getaddrinfo(host, port)[0][-1]) #接続確立
if __name__ == '__main__':
while True:
msg = input('--->>> ')
s.sendall(msg) #入力された文字列を送信
実際に動作させてみる
先にサーバ側のプログラムを実行させ,ソケットの待受を開始する.
こんな感じでクライアント側で入力した文字列がサーバ側でリアルタイムで確認できるようになる.
ソースコード:解説していくよ
TCPサーバ
micropythonにはソケット通信を行うためのモジュールが標準的に組み込まれています.
解説はmicropythonの公式ドキュメントを参照しつつ行います.
listenSocket = socket.socket() #socketを作成
簡単に言えばここでソケットを生成します.オプションも付けられます.
listenSocket.bind((ip, port)) # ソケットを特定のIPアドレスとポートに紐付け
ソケットを特定のIPアドレスとポートに紐付けます.
引数addressと書いてありますが,ソースコード例のようにタプルで指定しないとダメです.
基本的にはIPアドレスとポートを渡せばOK
listenSocket.listen(5) # 接続の待受を開始
接続の待ち受けを設定します.
接続可能数を指定します.今回の場合では最大で5接続まで行えます.
listenSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) #指定されたソケットオプションの値を設定
ここが結構めんどくさい
ドキュメントに書いてある通りですが,引数のlevelとoptnameがチップボードによって異なるため,使うボードによって確認が必要です.
https://docs.micropython.org/en/latest/reference/glossary.html#term-MicroPython-port
conn, addr = listenSocket.accept() #接続を受信
書いてある通りですが,戻り値はconnとaddressの2つです.
connは接続でデータを送受信するために使用できる新しいソケットオブジェクト.
addressは接続のもう一方の端のソケットにバインドされたアドレス.
data = conn.recv(1024) #一度に受け取るデータのサイズを指定
たまたまpythonの公式ドキュメントで見つけたんですが,こんなものがありました
注釈 ハードウェアおよびネットワークの現実に最大限マッチするように、 bufsize の値は比較的小さい2の累乗、たとえば 4096、にすべきです。
ということですので,$2^{10} = 1024$でひとまず設定しておきます.(もっと小さくてもいいと思います)
conn.close() #接続を切断
接続を切断します.
TCPクライアント
s.connect(socket.getaddrinfo(host, port)[0][-1]) #接続確立
と簡単に書いてあったのですが,,,
よくよく読むと,こうやって使ってね,と推奨されるやり方があったのでこれを真似しました.
s.sendall(msg) #入力された文字列を送信
ソケットにデータを送信する.
おわりに
公式ドキュメント,
英語だけどめげずに読むことが大切だということですね