Open4
socket.ioの公式ドキュメントを読む
概要
- socket.ioは低遅延、双方向、イベントベースの通信を行う。
- websocketだけではなく、HTTP long-polling, WebTransportもサポートしている。ブラウザやネットワークの状況(e.g., websocketがブロックされてないかとか)を見て、適切な通信方法を選んでくれる。
- server側は、node.js, python, java, golang, rustとかも使える。client側もswift, kotlinとか使える
注意点
- socket.ioはwebsocket実装ではない。なので、ふつうのwebsocketクライアントはsocket.ioサーバには繋げない。逆に、socket.ioクライアントは普通のwebsocketサーバにはつなげない。
- プレーンなwebsocketサーバなら、wsなどを使うのが良い。
特徴
- websocketが繋げないときはhttp long-pollingにフォールバックしてくれる
- websocket接続が切れたときに再回復してくれる。これのために、定期的にheartbeatを送ることにより接続をチェックしている。接続がきれると、送るべきパケットを自動的にバッファリングしてくれる
-
socket.emit
でイベントをpublish、socket.on
でイベントをsubscribeする形で、イベントベースの書き方ができる -
emit
は、すべての接続済みクライアントに対してメッセージを送ることもできる(broadcasting)し、その中の特定のsubsetに送ることもできる - namespaceという概念があり、1つの接続の中で、複数のロジックを分離できる。HTTP通信で言う「パス」的な概念が使える。
Socket.ioはなぜ必要?
- 正直、websocketは現代ではほとんどすべてのケースで使えるのでそこの旨みは少ない。ただ、reconection、イベントベースの書き方やbroadcastingは必要になるケースが多い。
プレーンなwebsocketに比べたオーバーヘッドは?
-
socket.emit
するときに、何バイトかの余分なデータが通信にのる
Socket.IOの仕組み
- socket.ioの中身は、低レベルなエンジンであるEngine.IOと、高レベルAPIであるSocket.IOに分かれている。
- Engine.IO: 様々な通信方式(e.g., websocket, http)のサポートと、切断検知を行う
- connetionを始める時のハンドシェイク
- 最初の接続時はhttp long-pollingで行い、その後可能ならwebsocketにupgradeする
複数のサーバで使うには
sticky-session (http long-pollingのみ)
- http long-pollingを有効にしている場合は、sticky-session (=クライアントが必ず同じサーバに接続する)を担保する必要がある。
- websocketで基本やる場合は不要。(=なぜならwebsocketは1つのtcp connectionで1つのsession全体の通信を行うから)
サーバ間でのデータ共有
- adapterを使う。redisやmongo、cloud pub/subが使える。
- 例えばredisのケースだと、下記の用に、redisを介してemitしたイベントを他のサーバに伝達する。
eventのemit/listenの仕組み
接続の中で閉じた送信
- socket (=接続しているconnection)に対して、
socket.emit
とすると、接続中のsocketに対してイベント送信できる。socket.on
で、それをlistenできる。
broadcast (サーバ側からのみ)
-
socket
インスタンスではなく、io
インスタンスからio.emit
すると、すべてのclientに対してイベント送信できる。 - また、
socket.broadcast.emit
とすると、そのsocketに接続しているclient以外のすべてのclientに対してイベント送信できる。
特定のroomへの送信 (サーバ側からのみ)
- roomは、参加・退出が可能なチャネルのような概念。
-
socket.join
で、任意の名前のroomに参加できる。 -
io.to('ルーム名').emit
で、特定のroomのすべてのクライアントにイベント送信できる。toを連鎖させることにより、複数のroomにも送れる -
socket.to('ルーム名').emit
で、そのsocketに接続しているclient以外の、特定のroomのすべてのクライアントにイベント送信できる。