Articles今更だけどSocket.ioについてまとめてみるちょっとSocket.ioを導入する機会があったので、色々調査したのをメモしておきます。Socket.ioとはnode.jsのnpmとして提供されている、WebSocketを手軽に扱えるモジュールです。すごい有名なので、だいたいみなさん知ってると思います。他にはwebsocket-serverとかもあるんですが、こっちの方が有名ですかね。特徴として、クライアントサイドのトランスポートがクロスブラウザなところでしょうかね。詳しいところは公式サイトを見るといいと思います。apps.すんごい出たばっかりの頃にも触ったことがあったんですが、今使ってみると機能がすごい増えててびっくり。機能の紹介とかは他のサイトを見てもらうとして、備忘録的に自分がやった所なんかをまとめておくことにします。pm2で複数プロセス起動するパターンです。socket.ioのデフォルトはオンメモリなのでプロセス間でコネクションの共有ができず。RedisのPubSubで共有するようにしています。このあたりのstoreもサポートしてるあたりすごいですね。接続サーバ側はロードしてlistenすればOK。});<p>以前はhttpのラッパーで動作していたようですが、単体で動かせるようになってますね。あと、クライアント側はサーバ側のlistenがスタートしていないとスクリプトがServeされないので注意</p><h4>設定周り</h4>configureまたはsetメソッドで設定を変更。listenメソッドの第二引数にオプションを渡せるみたい。});<p>configureメソッドで設定する場合、第一引数にはnode環境変数に対応した設定が記述できるみたい。上記の場合、</p>NODE_ENV=development<p>とか設定して起動すると、その値に応じた設定で起動できる。ログレベルの変更とかにいいですかね。普通にsetメソッドだとグローバルな設定になるようです。デフォルトではログがすんごいダーってでるので、私はlog_levelを変更しています。</p><h4>RedisでPub/Sub</h4><p>socket.ioのデフォルトストアはオンメモリなので、複数間プロセスでのコネクション共有にはRedisが使える。}));<p>Pub/Sub/Clientそれぞれで違うサーバを使えるみたい(未検証)。実際にRedisサーバを起動してやってみたらちゃんと共有されているようでした。</p><h3>コネクションセグメントの設定</h3><p>of()メソッドでコネクション毎にセグメンテーションを切ることができるようになっていた。(内部ではroomって書いてあるので、チャットルームみたいなイメージかも)。今回は、管理者サイドと顧客サイドでセグメントを切ってコネクションを管理。指定がなければof('/')とルートになるみたい。roomもまたServerインスタンスになる<h3>認証</h3><p>authorization()メソッドで認証が可能。});<p>io自体にauthorizaton()メソッドをコールすると、グローバルな認証になる。});<p>引数がクロージャになっており、handshakeにはリクエスト情報が入る。結果[true/false]);とすることで、認証の成功/失敗が行える。handshakeにはリクエストヘッダとかoriginしか入らないので、厳密にはID/PASSな認証は難しかった。今回は別途認証フローを作ることで対応した。このへんもうちょっと調査したほうがいいかも。</p><h3>配信(シングル応答、ブロードキャスト、コネクション指定</h3><p>接続後はsocketインスタンスにイベントを設定していって、任意のタイミングで配信するようになっている。});<p>イベント周りはおなじみEventEmitterを継承しているのでそれっぽい感じみたい。配信はsocketのプロパティでいろんな配信形式が取れる。‘hoge’);<p>socketに対して行うと接続毎に配信、ioに対して行うとグローバルな配信(ブロードキャストみたいな感じ)になる。</p><h3>再接続に関して</h3><p>今回ハマったのはここ。出てくるWebSocketのアプリ(チャットとかがほとんど)は、基本的にページを開いた瞬間にはんどシェイクしてそのままなので問題はなさそうなんですが、今回は任意のタイミングで接続をオープン/クローズでき、再接続も可能な感じにする必要がありました。試した所、</p><h4>一度io.connect()が呼ばれると、内部でsocketインスタンスが生成され、二回目はそのインスタンスが使いまわされる</h4><p>という感じの挙動でした(内部までコード見てないので、あくまで推測)。connected<p>ちょっとわかりづらいですが、接続完了後、3秒時間を置いて接続を遮断、再接続を試みるコードです。これを実行すると、最初は「connected」と出るんですが、2回目からは何も表示されない、つまりconnectイベントがemitされません。この辺りのドキュメントがあんまり探せなかったんですが、結論からいうと、</p><h4>io.connect()は初回呼び出しの場合だけ接続をスタートする</h4><p>という感じなのかなーと。上記のコードでは、2回目の再接続にもio.connect()を使っているため、イベントが発火されなかったんですね。代わりにどうするかというと、2回目は1回目の接続に使用したsokcetをconnectするようです。</strong>とすることで、再接続ができ、connetcイベントも発火するようになりました。まとめると、一度接続したsocketはどこかにプールしておき、2回目はそれを使いまわすようにする、ってことですね。io.connect()はシングルトンなんでしょうかね。</p><h3>まとめと感想</h3><p>ざっと触りだけ書いてきましたが、確かに接続周りはすんごく便利ですね。イベント駆動なアプリになってしまうので、アプリケーション側はしっかり設計しないとカオスな感じになると思います。Deferred使うとか、flow.js使うとか、フロー制御できるライブラリと一緒に使うといいと思います。2013node.js。