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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

WebSocket

WebSocketとは双方向・全二重コミュニケーションのためのAPIでありプロトコルのことを指します。WebSocketはHTML5に密接に結びついており、多くのウェブブラウザの最新版に導入されています。

Q&A

解決済

2回答

4639閲覧

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

takeiy

総合スコア6

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

WebSocket

WebSocketとは双方向・全二重コミュニケーションのためのAPIでありプロトコルのことを指します。WebSocketはHTML5に密接に結びついており、多くのウェブブラウザの最新版に導入されています。

1グッド

0クリップ

投稿2019/10/22 13:41

前提・実現したいこと

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

該当のソースコード

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

Python

1import websocket 2 3""" 中略 """ 4 5class sock: 6 def __init__(self, api_key, api_secret): 7 websocket.enableTrace(True) 8 self.ws = websocket.WebSocketApp(endpoint, 9 on_message=self.on_message, 10 on_error=self.on_error, 11 on_close=self.on_close, 12 on_open=self.on_open, 13 header=self.__get_auth()) 14 self.wst = threading.Thread(target=lambda: self.ws.run_forever()) 15 self.wst.daemon = True 16 self.wst.start() 17 18 def on_message(self, ws, message): 19 message = json.loads(message) 20 pprint(message) 21 22""" 中略 """ 23

事象

基本的な動作は問題なく、正常に動くのだがイベントが一時的に増え、送信情報が混みあったときに送られてくるはずのメッセージが欠落しているようでその後の処理に誤動作を起こす。
欠落していることの確認はpprintで受け取ったmessageを表示させているがそこにないことから判明。
ただここまで来たが、これからどんなデバック、対策を取ればいいのかわからず、こちらにご相談させていただきました。

仮説1)情報が欠落することがwebsocketの仕様
→混みあったときにはサーバ側として送れるものだけ送るという仕様であればチャンネルを減らすなどして負荷低減を行う、もしくはそれを前提にREST APIで情報を補完する処理を入れる、という対策が考えられる。

仮説2)自分のプログラムの処理が間に合わず、ライブラリなどが受け取ったmessageを意図的に捨てている。
→そうであれば処理の高速化や捨てるmessageの優先順位などを付けられないか、という対策が考えられる。

仮説3)本当は正常にすべてのmessageを受け取っているが、自分のプログラムミスにより表示できていない
→on_messageの開始時に表示させているため、受け取ったものはすべて表示できているはず。。
ただ情報は欠落しないということになると今度は処理が遅く、受信情報がたまってきてリアルタイム性が失われる仕様であれば、それについても別途対策の検討が必要になる可能性。

Webで検索しましたが、Websocketの情報欠落に関する情報が見当たらず、ご意見等いただけますと幸甚に存じます。
よろしくお願いします。

補足情報(FW/ツールのバージョンなど)

Windows10
Python 3.7.1
Pycharm

set0gut1👍を押しています

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_waiwai

2019/10/22 15:58

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

回答2

0

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

投稿2019/10/23 15:33

takeiy

総合スコア6

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

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/22 17:48

編集2019/10/22 18:00
dodox86

総合スコア9183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takeiy

2019/10/23 01:19

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問