Open4

socket.ioの公式ドキュメントを読む

nakaakistnakaakist

https://socket.io/docs/v4/

概要

  • 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するときに、何バイトかの余分なデータが通信にのる
nakaakistnakaakist

Socket.IOの仕組み

https://socket.io/docs/v4/how-it-works/

  • socket.ioの中身は、低レベルなエンジンであるEngine.IOと、高レベルAPIであるSocket.IOに分かれている。
  • Engine.IO: 様々な通信方式(e.g., websocket, http)のサポートと、切断検知を行う
    • connetionを始める時のハンドシェイク
    • 最初の接続時はhttp long-pollingで行い、その後可能ならwebsocketにupgradeする
nakaakistnakaakist

複数のサーバで使うには

https://socket.io/docs/v4/using-multiple-nodes

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したイベントを他のサーバに伝達する。
nakaakistnakaakist

eventのemit/listenの仕組み

接続の中で閉じた送信

https://socket.io/docs/v4/emitting-events/

  • socket (=接続しているconnection)に対して、socket.emitとすると、接続中のsocketに対してイベント送信できる。socket.onで、それをlistenできる。

broadcast (サーバ側からのみ)

https://socket.io/docs/v4/broadcasting-events/

  • socketインスタンスではなく、ioインスタンスからio.emitすると、すべてのclientに対してイベント送信できる。
  • また、socket.broadcast.emitとすると、そのsocketに接続しているclient以外のすべてのclientに対してイベント送信できる。

特定のroomへの送信 (サーバ側からのみ)

https://socket.io/docs/v4/rooms/

  • roomは、参加・退出が可能なチャネルのような概念。
  • socket.joinで、任意の名前のroomに参加できる。
  • io.to('ルーム名').emitで、特定のroomのすべてのクライアントにイベント送信できる。toを連鎖させることにより、複数のroomにも送れる
  • socket.to('ルーム名').emitで、そのsocketに接続しているclient以外の、特定のroomのすべてのクライアントにイベント送信できる。