こんにちは。
先日、ESP32とサーバーでのWeb Socket通信でハマったのでそのことを書こうと思います。
ベースのリポジトリはこちらです。
(Documentationは全然できていません。)
サーバー側
クライアント側(ESP32)
システム構成
システム構成としては
サーバー
サーバーはUbuntuサーバー・PythonでサーバーWebSocketで制御信号をESP32に送る。
クライアント
クライアントはESP32でサーバーに接続してSocketの制御信号を受信できるように待機して、信号を受信する。
ハマったデッドロック事象
ESP32がデッドロックしたコードはこんな感じ。
サーバー側実装例
サーバー側はクラインアントからの接続を待機して、接続があったら今度は、制御シグナルが来るまで待つようなタイムアウトのない実装となっています。
クライアント側実装
クライアント側はサーバーに接続後、サーバーからのSocketでの制御信号が来るまで待機(Loop)するような実装となっています。
問題事象
発生したデッドロックはクライアント側です。
簡単に言うと、client.connect()で接続した後に長時間(30分程度)なんのメッセージがないままになるとclient.connected()はTrue(接続済み)を示すのですが、実際は接続されていません。
つまり、接続したまま長時間待機で切断されるがその結果がClientのクラス・インスタンスに反映されません。
なのでデッドロック(切断も再接続もしない)に陥ってしまいます。
対策
問題事象はクライアント側で発生しましたが、サーバー側に対策を行いました。
要は長時間接続したまま制御信号を送らないという状態を作らなければいいわけです。
サーバー側の対策はこんな感じです。
クライアントからの接続が完了して5分経っても制御メッセージが来ない場合にタイムアウト処理をして一旦接続を切断します。
するとクライアント側は切断され再接続を行うので、デッドロックに陥りません。
こちらで対策完了です。