質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.92%

Websocket通信にて情報が欠落する (Python)

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 1,460

score 6

前提・実現したいこと

Websocket通信にて情報が欠落することの対策を取りたいが、いまどのような状態になっているのかわからず、デバック方法を含めて対策を検討したい。
目的としてはコードというよりもwebsocketの仕様についての見解をいただけたら幸いです。

該当のソースコード

コードが長すぎるので省略しながら記載しますが、基本的にはwebsocketにてon_messageのあと一度なにを受信したものを表示させてその後の処理を行っています。
よって受信したmessageは必ずpprint表示させています。

import websocket

""" 中略 """

class sock:
    def __init__(self, api_key, api_secret):
        websocket.enableTrace(True)
        self.ws = websocket.WebSocketApp(endpoint,
                                         on_message=self.on_message,
                                         on_error=self.on_error,
                                         on_close=self.on_close,
                                         on_open=self.on_open,
                                         header=self.__get_auth())
        self.wst = threading.Thread(target=lambda: self.ws.run_forever())
        self.wst.daemon = True
        self.wst.start()

    def on_message(self, ws, message):
        message = 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

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • y_waiwai

    2019/10/23 00:58

    具体的な通信内容を、正常な場合と欠落してる場合のものを提示しましょう

    キャンセル

回答 2

checkベストアンサー

0

回答と言うよりは、意見です:

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よりは優先度は低いかと思います。

。。。と、そんなところの意見です。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/10/23 10:19

    とても貴重なご意見ありがとうございます。
    たしかにおっしゃるとおりまずは本当に送られてきているかどうかを観るべきですね。
    WireSharkを使ってみようと思います。

    キャンセル

0

いろいろな方に相談した結果、サーバーを信用しすぎるのは良くないという結論になり、情報の欠落を前提としてREST APIで補完する仕様に決めました。
貴重なご意見ありがとうございました。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.92%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る