LoginSignup
67
67

More than 5 years have passed since last update.

socket.ioのパケットを(触りだけ)キャプチャ

Last updated at Posted at 2015-09-29

socket.io(利用バージョンは@1.35)がどんな通信をしているのかな?と思い、Web知識の浅い、Node.jsの扉を叩いている程度のレベル(websocketってなに?のレベル)の私が、socket.ioの理解を目的として、googleでの情報収集+実際にキャプチャ(触り程度です。パターンも少ないです。。)しながら、備忘の為にまとめた内容です。
従って、誤りや、ずれてるところも多々あると思います。

socket.io概要

socket.io は シンプルなAPIでリアルタイムWebを実現する為のモジュール。

ググってみると、同モジュールは websocket と ロングポーリング( polling ) をサポートしており、 モジュール内部で自動に最適な接続方法( transports )を選択し、通信経路を提供します。こちらを参照すると、 polling はファイアウォール対策のだそうです。

ポーリングについては、こちら などが勉強になるかと。

古いバージョンでは以下の transports 群をサポートしていたそうです。

  • websocket
  • flashsocket
  • htmlfile
  • xhr-polling
  • jsonp-polling

が、socket.io@1.35時点では

  1. polling(jsonp/xhr)
  2. websocket

の二つのみとなっています。(こちらより)
該当バージョンでは、最初に polling で試して、その後可能だったら、 websocket に自動で更新( upgrade )されるそうです。

このあたりのプロトコル周りは、"@1.00"付近から分離したらしい engine.io ( engine.io-protocol など) が担とのことで、 同モジュール次第ですね( 現時点サポートのサポートは、https://github.com/Automattic/engine.io#transports を参照)。

初めから transports に限定する(例えば websocket のみなど)ことも可能らしいのですが、 下名の理解が、浅い為、socket.io@1.35 で設定する方法をみつけることはできませんでした。

transports に限定は、io.set()ではうまくいかなかった。。

ちなみに、 polling なら古いブラウザでもいけるかなと思い

  • Mozilla/5.0 (Solaris10_9-19 i86pc) Gecko/20090623

で試したところ、 polling 接続が行えませんでした。

パケットの流れ

ざっくり以下のパターンをキャプチャしてみました。

  • 基本的な接続~送受
  • polling中(websocket確立前)のデータ送受
  • pollingとwebsocketの確立のタイミング
  • 経路断時の振る舞い
  • server側からのclose
  • client側からのclose

基本的な接続~送受

大きな流れは、以下の通りです。

  • Step 1 HTML及びsocket.io.js他の取得
  • Step 2 socket.io セッション開始
  • Step 3 polling開始
  • Step 4 websocketへのUpgrade
  • Step 5 websocket経路のデータ送受
  • Step 6 Ping-Pong(接続確認)

基本的な流れ.png

Step1 HTML及びsocket.io.js他の取得

  • 通常のHTTPコネクションです。ページ情報や、スクリプト情報を取得します。

Step2 socket.io セッション開始

  • clientのスクリプト内の接続指示( var socket = io(); )により、GETメソッドで接続要求がなされます。serverは応答で以下を返します。
    • session id(sid) ← websocket内で用いるKEY情報とは異なります。
    • websocketへの upgrade 可能か。
    • websocket Ping 間隔
    • websocket Ping Timeout間隔
      • Ping周りの設定方法は現時点、未調査。
  • HTTPメッセージを用います。

Step3 polling開始

  • clientよりポーリングを開始します。 この例では、ポーリング中にメッセージの送受が無かったものとしています。 この時点で、メッセージの送受が発生した場合については、後述します。
  • HTTPメッセージを用います。

Step4 websocketへのUpgrade

  • clientよりwebsocket用の新しいポートで接続を確立し、 websocket で規定される opening handshake を行います。
  • HTTPメッセージを用います。
  • websocketパケットを用いて、送受を確認します。(ping-pong)。
  • この時、既に発行ずみのpolling要求は"noop(no operation)"として終えます。
  • pollingwebsocketupgrade が完了します。
  • 後述しますが実際は、"polling開始"と並列で動作するようです。

websocketのデータフレーム

#
# "RFC6455":https://tools.ietf.org/html/rfc6455 より抜粋
#
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 ...                |
+---------------------------------------------------------------+
  • 上記の様に、通常のHTTP通信の様にHTTPヘッダが付きません。
  • clientからのパケットは、セキュリティ上Mask(暗号化)されます。 ( こちら より )

Step5 websocket経路のデータ送受

  • 任意のタイミングで送受します。

Step6 Ping-Pong(接続確認)

  • 接続確認の為、定期的(Step2のserverからの指定間隔)にclientからPingを送信し、serverはPingでそれにこたえます。
  • websocketパケットを用います。
  • Pongが途絶えても、指定timeout時間(Step2のserverからの指定間隔)を超えなければ、接続は保たれます。(詳細後述します。)

polling中(websocket確立前)のデータ送受

  • ここでは、polling中(すなわちwebsocket確立前)に、データの送受が発生した場合についてまとめます。大きな流れは以下の通りです。

    • 「Step 3 polling開始」内
      • Step 3-1 主接続ポートでのpolling
      • Step 3-2 polling用ポートでのpolling
  • client側は、ページ情報を取得した「主接続用ポート」で POST メソッドを通じでデータを送信します。
    server側は、 GET メソッドを用いたpollingに対する応答として、データを送信します。

  • pollingで用いるポートは、出足は「主接続ポート」を用い、別途並列で確保を試みる「polling用ポート」が開き次第、新しく確保した後者のポートを用います。

polling中.png

pollingとwebsocketの確立のタイミング

  • pollingとwebsocketの確立タイミングは、下図のように並列で動く様です。 最終的に、websocketのupgradeパケットまでにpolling経路が終端され、websoketに upgrade されます。

pollingとwebsocketの確立タイミング.png

経路断時の振る舞い

  • 前述 Step6 で記した様にwebsocket層で、keep-alive的な通信確認を実施しています。
  • 経路が途絶える(LANケーブルを抜く)と、指定timeout時間(Step2のserverからの指定間隔)を超えなければ、接続は保たれます。
    その間、送信されたデータは、経路復旧時に再送されます。下図 CaseA参照。

  • 指定timeout時間を超えた後に経路復旧すると、 Step 2 より再開します。

  • いずれしても、TCPレベルで接続が切れていなければの話となります。

経路断時の振る舞い.png

server側からのclose

  • websocket経路で、server → client へcloseが送信され、 その後逆に、client→serverに同様のcloseが送信されます。

その後 FIN がserver側から送信されます。

  • この時、「主接続用」と「polling用」はcloseされずに、保持されます。
  • また、server側に、再接続コードを埋め込むと、「主接続用」と「polling用」は再利用されます。
    • 完全にcloseする方法、要確認。。 再接続コードを記述しないと、pollingが勝手に始まるっぽい。。。(正しくpollingされているかまでは、未調査)

server_close.png

  • 利用コード。(サーバ側)
    :
  setTimeout(function() {
       io.close();
       http.listen(3000, function(){       // 再度listenしないと、再接続しない。
           console.log('listening on *:3000 --');
       });
  }, 10000);
    :

client側からのclose

  • websocket経路で、client→server へcloseが送信され、
    その後 FIN がserver側から送信されます。

  • この時、「主接続用」と「polling用」はcloseされずに、保持されます。

  • 再接続コード、要調査。

client_close.png

  • 利用コード。(client側)
    :
   socket.on('timer', function(msg){
       console.log('timer rise!');
       socket.close();
       socket = io();
      });
    :

利用環境

調査不足のところ

  • transports の指定方法
  • ping-pong間隔指定方法
  • close方法(接続の後始末) 及び 再接続方法。
    • sessino管理
  • バイナリ送受
  • etc..
67
67
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
67
67