跳到主要内容

SocketIO

Protocol

WEBSOCKET wss://example.com/socket.io/?EIO=3&transport=websocket
  • EIO - 版本 - 3/4
    • EngineIO v2 -> SocketIO v0.9
    • EngineIO v3 -> SocketIO v1, v2
    • EngineIO v4 -> SocketIO v3
      • reverse ping/pong
        • server -> client
        • 因为 client 的 timer 不一定靠谱
      • long-polling base64 binary data
      • record separator \x1e
        • 之前使用 length - 对于非 utf16 客户端实现不友好
  • transport - 传输协议 - websocket/polling
  • sid - session id

polling

  • Content-Type: application/octet-stream
  • Content-Type: text/plain; charset=UTF-8
  • <packet type>[<data>]<separator><packet type>[<data>]<separator><packet type>[<data>][...]

WebSocket

  • <packet type>[<data>]
<- 0{"sid":"258c675c-a211-4bd4-a861-7b2ae022309e","upgrades":["websocket"],"pingInterval":25000,"pingTimeout":60000}
<- 40

-> 2
<- 3

engine.io type

Nfor
0open
1close
2ping
3pong
4message
5upgrade
6noop

open

{
"sid": "lv_VI97HAXpY6yYWAAAC",
"upgrades": ["websocket"],
"pingInterval": 25000,
"pingTimeout": 20000,
"maxPayload": 1000000
}

socket.io action

Nfor
0CONNECT
1DISCONNECT
2EVENT
3ACK
4ERROR
5BINARY_EVENT
6BINARY_ACK
  • 40 -> message/CONNECT
-> { type: CONNECT, namespace: "/admin", data: { "token": "123" } }
<- { type: CONNECT, namespace: "/admin", data: { sid: "iLnRaVGHY4B75TeVAAAB" } }
  • type, namespace, data
  • CONNECT -> CONNECT,CONNECT_ERROR
  • EVENT, BINARY_EVENT -> ACK, BINARY_ACK
<packet type>[<# of binary attachments>-][<namespace>,][<acknowledgment id>][JSON-stringified payload without binary]

+ binary attachments extracted

编码

{ "type": "CONNECT", "namespace": "/admin", "data": { "sid": "oSO0OpakMV_3jnilAAAA" } }
0/admin,{"sid":"oSO0OpakMV_3jnilAAAA"}

参考

FAQ

namespace vs room

相同点

  • 命名空间和房间都是在服务端创建
  • 服务器只会将消息分发给连接到了相应命名空间和房间的客户端

不同点

  • 一个命名空间一个连接,一个命名空间下的房间共享一个连接
  • 客户端可任意离开房间,但要离开命名空间只能断开连接
  • 客户端只能连接到服务器上已经存在的命名空间
  • 只能在服务器端进入房间,但实现一个从客户端控制服务端加入房间的命令很简单.
  • 命名空间可进行授权验证
  • 房间虽然不支持授权验证,但自定义一个授权验证还是很容易的.
  • 房间是命名空间的一部分,默认为 'global' 命名空间

因此使用命名空间最好使用服务器上已经定义好的,而房间主要用于动态创建的.