質問: json.loads(message) pprint(message) """ 中略 """ ``` ### 事象 基本的な動作は問題なく、正常に動くのだがイベントが一時的に増え、送信情報が混みあったときに送られてくるはずのメッセージが欠落しているようでその後の処理に誤動作を起こす。 欠落していることの確認はpprintで受け取ったmessageを表示させているがそこにないことから判明。 ただここまで来たが、これからどんなデバック、対策を取ればいいのかわからず、こちらにご相談させていただきました。 仮説1)情報が欠落することがwebsocketの仕様 →混みあったときにはサーバ側として送れるものだけ送るという仕様であればチャンネルを減らすなどして負荷低減を行う、もしくはそれを前提にREST APIで情報を補完する処理を入れる、という対策が考えられる。 仮説2)自分のプログラムの処理が間に合わず、ライブラリなどが受け取ったmessageを意図的に捨てている。 →そうであれば処理の高速化や捨てるmessageの優先順位などを付けられないか、という対策が考えられる。 仮説3)本当は正常にすべてのmessageを受け取っているが、自分のプログラムミスにより表示できていない →on_messageの開始時に表示させているため、受け取ったものはすべて表示できているはず。。 ただ情報は欠落しないということになると今度は処理が遅く、受信情報がたまってきてリアルタイム性が失われる仕様であれば、それについても別途対策の検討が必要になる可能性。 Webで検索しましたが、Websocketの情報欠落に関する情報が見当たらず、ご意見等いただけますと幸甚に存じます。 よろしくお願いします。 ### 補足情報(FW/ツールのバージョンなど) Windows10 Python 3.7.1 Pycharm
回答: 回答と言うよりは、意見です: WebSocketはTCPのコネクションを使って送受するプロトコルなので、**欠落、欠損は無い**のが前提のはずです。それが前提にあるなら、UDPを採用していたと思います。(しかしそれではWebSocketを名乗る意味が無い) WebSocketの情報についてWEBで検索した、とありましたが、RFCの方はご覧になりましたでしょうか。RFC6455がそれです。 IETF - RFC6455 The WebSocket Protocol 非公式日本語訳版 - RFC 6455, The WebSocket Protocol 多くの製品レベルのWebSocketサーバー/クライアントの実装はこれに基づいているはずですが、RFCは仕様と言うよりは勧告(こんな仕様でやったらどうでしょうか、と言うかんじ)に近い部分があり、一部の機能はMUST(=しなければならない)やSHOULD(=すべきである)などとして、実装者に判断を委ねる場合があります。今回の事象がそれにあたるかは分かりませんが、少なくとも、軽く読んだ限りではデータの欠損を思わせる記述は見当たりませんでしたし、WebSocketはHTTPをベースにした部分がありますから、それも当然です。広く使われているRFCのプロトコルであれば、RFCに準拠していない実装は市場から消えていくだろうし、気に留めつつも仕様の時点でその辺りは心配は無いと思います。 サーバー/クライアントの実装では`on_message`のようなメソッドを使い、いちメッセージを受信したときにイベントとしてコールバックするようなケースが多いようですが、プロトコルの下の方を見ると、TCPコネクション上でのストリーム指向のシリアルデータを、WebSocketを実装するサーバー/クライント側のライブラリが、単一のメッセージとして扱えるよう、頑張って分解~再構築をしています。上位アプリが取り出さないメッセージがあれば、取り出されるまではライブラリ内部でキューとして保存しているでしょう。 質問者さんと同じ事象ではありませんが、私もAndroidのWebSocketクライアントでライブラリに起因する問題に少し、悩まされたことがあります。ライブラリのJavaでの実装を読んでみると、受信と送信で別スレッドによるメッセージキューの管理をしており、ポンプのように処理をしていました。 「これはライブラリの実装次第で、様々な問題が入り得るかなー。」と感想を持ったものです。質問者さんがお使いのPython用のWebSocketモジュールのソースを読んだ訳ではありませんが、ライブラリに起因する問題かもしれません。 本当に受信データが欠落しているかは、WireSharkのようなパケットキャプチャーソフトを使って、ネットワークインターフェース上では本当に受信できているデータと、ソフト側で受信した(と認識している)データを付き合わせる必要があると思います。クライアント側のネットワークインターフェース上で受信が確認できないならば、サーバー側の送信の時点で欠落しているのかもしれません。 上記のような検証が大変なのであれば、あとはアプリ側でリカバリーできるようにするしかありません。例えばメッセージにシーケンス番号を付与して、受信側が欠落を認識したら、そのシーケンス番号のものについて再送を要求できるとか。 そんな訳で、質問者さんの仮説に対する私の意見としては、 > > 仮説1)情報が欠落することがwebsocketの仕様 > > > TCPコネクションを使うWebSocketではそれは無いはず。検証においては優先度低め。あくまで疑うならWireSharkのようなパケットキャプチャーソフトを使って検証。欠落しているのであれば、送信側を疑って良いかも。 ※出入口は疑い無し(=ネットワークインターフェース上の入出力は正しい)が前提となるので、検証ではむしろこの部分の疑いを晴らしておくのが先決かもしれません。 > > 仮説2)自分のプログラムの処理が間に合わず、ライブラリなどが受け取ったmessageを意図的に捨てている。 > > > 個人的にはこれが1番かと思います。 > > 仮説3)本当は正常にすべてのmessageを受け取っているが、自分のプログラムミスにより表示できていない > > > 有り得ますが、on_messageの開始時に表示させているとのことなので、仮説2よりは優先度は低いかと思います。 。。。と、そんなところの意見です。