ということで、まず Engine.IO を調査してみた。 websocket だけの実装ではだめっぽいので、少なくとも polling/xhr は必要そう。
XHR クライアントに限定したら簡単に実装できそうかなあという印象。 upgrade 周り含めるとちょっと面倒そう。 あと、Ack は Engine.IO には含まれてないので Socket.IO まで見る必要がありそう。
次は、簡易でいいので Engine.IO の Go クライアントを用意してみる。
以下メモ。
https://github.com/socketio/engine.io-protocol https://github.com/socketio/engine.io-parser https://github.com/socketio/engine.io-client
Transport は Engine.IO の URL に対して接続を確立する サーバは open に対して sid, upgrades, pingTImeout, pingInterval を含む返信をする サーバは ping に対して pong しなければならない クライアントとサーバは message パケットを自由に交換する(おそらく Request-Response のように対になることなくそれぞれ勝手に、という意味) Polling している Transport はソケットを閉じるため close を送ることができる?since they're expected to be "opening" and "closing" all the time.
がよくわからん
URL は/engine.io/[?<query string>]
という形式。 query はオプショナルで、transport
, j
, sid
, b64
の 4 つが予約されている。 transport は Transport 名で、デフォルトではpolling
かwebsocket
j は transport がpolling
で JSONP response が要求されている時、JSONP response index が設定される sid はセッション ID。クライアントがセッション ID を与えられたら指定する必要あり b64 はクライアントが XHR2 をサポートしていない時 b64=1 となって、バイナリは base64 エンコードされて送られる
エンコーディング
packet と payload がある
packet は UTF8 文字列かバイナリデータ 文字列の場合、以下のフォーマット
<packet type id>[<data>]
バイナリでも同じだけど、packet type id
のところが最初の 1 バイトになる
パケットタイプは以下のものがある
0 open 新しい Transport が開いた時サーバからクライアントに送られる
1 close Transport を閉じる要求だが、自身のコネクションは閉じない? (Transport と Connection の違いがわからん?)
2 ping 3 pong Ping に来たデータをそのまま Pong する必要ある
4 message データをコールバックに渡して呼ぶ必要がある(プロトコルというよりライブラリの話)
5 upgrade Transport を切り替える前に新しい接続方法でいけるかテストする。テスト成功したらクライアントは upgrade を送って、新しい Transport に切り替わる。
6 noop poll cycle を強制するため incoming websocket connection を受け取った場合に使われる? (よくわからん)
payload
いくつかのパケットをつなげたもの
<length1>:<packet1>[<length2>:<packet2>[...]]
つまり長さとパケットが交互に来る形 length は文字数で表現する packet は上で説明した通り
XHR2 がサポートされていない時は base64 エンコードされた文字列として送信する それを示すために b という文字がくっつく
<length of base64 representation of the data + 1>:b<packet1 type><packet1 data in b64>
XHR2 がサポートされている時はこれ
<0 for string data, 1 for binary data><Any number of numbers between 0 and 9><the number 255><packet1 first type, then data>[...]
UTF8 文字列とバイナリデータの組み合わせが送信される時は、各文字の文字コードが 1 バイトずつ書き込まれる?
Payload は framing をサポートしていない transport で使われる。polling とか
Transport
websocket, polling がある polling には jsonp と xhr がある
polling は、クライアントからサーバに対する定期的な GET と、データ送信時の POST からなる
xhr では CORS レスポンスをサポートする必要がある jsonp ではサーバは正しい JavaScript を返信するよう実装する必要がある websocket ではフレーミングをサポートしているため payload は使ってはならない
connection は常に polling(xhr か jsonp)で開始する WebSocket は probe を送信するところでテストされ、probe が返れば upgrade される