MessagePack on socket.ioでのバイナリ転送案

前提

  • socket.io 1.3.5

socket.ioのroomかnamespaceか悩んだ末、問題はバイナリの転送だけなので、MessagePackなどを使えば良いのではないかと考えました。プロトコルも素直になるので。

MessagePack:JavaScript向けのライブラリではいずれもバイナリを文字列としてデコードする(MessagePackの仕様上は文字列とバイナリデータを区別しない)ので、バイナリを扱おうとすると処理系によってデータを変更されてしまう可能性があることがわかりました。

BSON:配列を使うとデータサイズが大きくなる(配列のインデックスを添え時にしたmapとして扱っている)という欠点があります(あとJavaScriptに依存しすぎた型も多いですが使わなければ良い)。配列バンバン使うのでまずいです。

Base64C++からJavaScriptにバイナリデータを渡すときにBase64エンコーディングをかける方法もありますが、単純にサイズが増えます。 (´・ω・`)ウ~ンMessagePackのライブラリを改造してUint8Arrayを戻す形にすれば良いかな?と調べたら改造済みのものがあるようです。

github.com

追記

などと調べていたら、socket.ioの1.0以降ではバイナリ転送(Blog, Uint8Array)を含むオブジェクトの転送が可能だそうです。

参考

Socket.IO — Introducing Socket.IO 1.0

socket.ioでサーバからクライアントへバイナリデータを送る際の送信元

前提

  • socket.io 1.3.5

socket.ioのroomにはsocket.io自体にクライアントがどのroomに対してメッセージを送ったか判別する手段がない。つまり、1ユーザが同時に複数のroomに所属する場合、どのroomにメッセージを送るかは送信メッセージ上で組み込む必要がある。JavaScriptで解析が面倒なバイナリデータを転送する場合はroom機能を使わないか、バイナリをbase64エンコードなどする必要がありそう(JSONにバイナリデータを格納した場合、バイナリセーフである確証が得られなかったため)。

もう一つ、namespaceという機能があり、この場合、どのnamespace宛にデータを送信したかsocket.ioで判定可能になる。ただし、namespaceから特定クライアントだけを切断したり、namespace自体を解散する公式なAPIが今のところ無いようだ。(roomは切断APIがあり、すべてのクライアントが切断した場合roomが解散される) 試した挙句、機能自体はnamespaceで作り、切断の機構を自作するしかなさそう。

参考

stackoverflow.com

stackoverflow.com

 

socket.ioのon('connect')とon('connection')の2通りの書き方があった

前提

  • socket.io 1.3.5

socket.ioの接続イベントはon('connection', <接続時に呼ばれる関数>)とマニュアルに書いているけど、プログラム中ではon('connect', <接続時に呼ばれる関数>)と実装されている。バグかドキュメントのミスじゃないかと調べたら、なんと両方動いた。マニュアルにないけど、of(, <接続時に呼ばれる関数>)でも同じ動作をする。このときはon('connect')が内部で呼ばれてた。

JavaScriptのlocation.hostが返す値にはポート番号が含まれる場合がある

前提

ブラウザのJavaScript、location.hostはlocalhost:8080のようにポート番号が付記される。ただしポート番号が80の場合はlocalhostだけとなる。サンプルを実行してlocalhostだからといって、ポート番号を結合するコード(location.host + ':8080')を書くとlocalhost:8080:8080となって接続できない、、、とおもいきや、socket.ioのnamespaceに接続する場合は何もエラーを吐かずに動かないだけ、原因究明にえらい時間を使った。