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

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

ただいまの
回答率

88.91%

Pythonでのパケットのデコード(?)について

解決済

回答 1

投稿 編集

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

wanna-be

score 20

pythonでのパケットのデコード

現在、独学でネットワークプログラミングについて勉強している者です。その途中で一つわからな
いことが出たので質問させていただきます。

今、websocketサーバーのソースコードをgithubから見つけ読んでいたのですが、
クライアントから到着したパケットを解析するメソッドにおいて

def _parseMessage(self, byte):
    self.fin = byte & 0x80
    self.opcode = byte & 0x0F
    rsv = byte & 0x70


(URLです。)
https://github.com/dpallot/simple-websocket-server/blob/master/SimpleWebSocketServer/SimpleWebSocketServer.py#L415

という記述を見つけました。self.finはメッセージの最後の断片であるかどうかを表すものであり、
self.opcodeはペイロードの解釈の定義、rsvは予約済みビットであることはRFCなどから理解で
きるのですが、なぜbyte & 0x80というふうにビット演算子を使用しているのかその意図がよくわ
かりません。
例えばself.finであれば

self.fin = byte & 0x80 
#これ↑は
128  = 129  & 128  # byteには129が渡されていました。また,0x80128でありました。


というふうになるのですが、なぜこうする必要があるのか。

下手な説明で申し訳ありませんが、よろしくおねがいします。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

+1

_parseMessage に渡ってくる1byteのデータの最初のbitがfinを表すためです。
最初のbit, つまり1byteの最上位ビットを調べたいので、 0x80 = 2進数表現だと 0b10000000 でマスクしています。

RFC 6455 The WebSocket Protocol - 5.2.  Base Framing Protocol から引用します

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-------+-+-------------+-------------------------------+
     |F|R|R|R| opcode|M| Payload len |    Extended payload length    |
     |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
     |N|V|V|V|       |S|             |   (if payload len==126/127)   |
     | |1|2|3|       |K|             |                               |
     +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
     |     Extended payload length continued, if payload len == 127  |
     + - - - - - - - - - - - - - - - +-------------------------------+
     |                               |Masking-key, if MASK set to 1  |
     +-------------------------------+-------------------------------+
     | Masking-key (continued)       |          Payload Data         |
     +-------------------------------- - - - - - - - - - - - - - - - +
     :                     Payload Data continued ...                :
     + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
     |                     Payload Data continued ...                |
     +---------------------------------------------------------------+

   FIN:  1 bit

      Indicates that this is the final fragment in a message.  The first
      fragment MAY also be the final fragment.

この図から、最初の1byte = 8bitの構成要素の内、0x80(=0b10000000)でマスクするとFIN, 0x0F(=0b00001111)でマスクするとopcodeが取得出来ることが分かります。

ソースコード中のコードをこれに従って読み解くと以下のようになります。

    self.fin = byte & 0x80  # 0b10000000でマスク
    self.opcode = byte & 0x0F  # 0b00001111でマスク
    rsv = byte & 0x70  # 0b01110000 でマスク

通信データのパケットでは、1byteの中に複数の情報を詰め込んでいるため、1byte未満のbit単位で値を解釈する必要があるため、このようにマスク処理をして、興味のあるbitの状態を確認します。このようなデータを読み解く際に、1byteのデータをそのまま10進数で解釈しないほうがよいです。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/03/14 23:19 編集

    余談ですが、Pythonのbin関数を使うと、bitの状態を視覚的に見易くなるのでデバッグ時に重宝します。

    >>> print(bin(129))
    0b10000001

    慣れてくると16進数表現でも十分に理解できるようになってきますよ。

    >>> print(hex(129))
    0x81

    キャンセル

  • 2017/03/14 23:26 編集

    早速の回答ありがとうございます。疑問が解決し、また、自分のパケットの図の解釈が間違っていたこともわかりました。これで先に進めます。ありがとうございました!

    キャンセル

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

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

関連した質問

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