← 戻る

GameLiftのGo用Server SDKを作ってみたい(2)

2020-02-17

ということで、まず 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 名で、デフォルトではpollingwebsocket 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 される