socket.io通讯原理

2,879 阅读3分钟

socket.io是websocket的超集,在不支持websocket的情况下使用轮询来进行兼容。

概念

socket.io是一个跨浏览器支持WebSocket的实时通讯的JS,封装了WebSocket和轮询等方法,会根据情况选择方法来进行通讯。支持客户端&服务端,编程体验统一。底层使用engine.io 封装了一层协议。

数据编码

engine.io使用websocket时有一套自己的ping/pong机制,使用的是opcode为0x1(Text)类型的数据帧,不是websocket协议规定的ping/pong类型的帧

engine.io的数据编码分为Packet和Payload,其中 Packet是数据包,有7种类型:

  • 0 open:从服务端发出,标识一个新的传输方式已经打开。
  • 1 close:请求关闭这条传输连接,但是它本身并不关闭这个连接。
  • 2 ping:客户端周期性发送ping,服务端响应pong。
  • 3 pong:服务端发送。
  • 4 message:实际发送的消息。
  • 5 upgrade:在转换transport前,engine.io会发送探测包测试新的transport(如websocket)是否可用,如果OK,则客户端会发送一个upgrade消息给服务端,服务端关闭老的transport然后切换到新的transport。
  • 6 noop:空操作数据包,客户端收到noop消息会将之前等待暂停的轮询暂停,用于在接收到一个新的websocket强制一个新的轮询周期。

Payload是指一系列绑定到一起的编码后的Packet,它只用在poll中,websocket里面使用websocket帧里面的Payload字段来传输数据。

// Payload格式
<length1>:<packet1>[<length2>:<packet2>[...]]
/** polling模式返回值
 * 这里总共有两个packet
 * 第一个长度为96,packet类型为open
 * 第二个长度为2,packet类型为message
 **/
96:0{"sid":"WJT_1iJwliSggnDFAAAB","upgrades":["websocket"],"pingInterval":25000,"pingTimeout":5000}2:40

链接过程

socket.io与websocket的链接过程有所不同,多了兼容模式以及心跳的模式。下图的模式采用的是兼容模式,transport: ['polling', 'websocket']

1.客户端发起polling请求

2.服务端同意请求,返回 0

3.客户端继续发起polling,请求数据

4.客户算发起webscoket握手请求

5.服务端同意链接websocket,此时状态码为101

6.客户端发送websocket探测帧:2probe(ping)

7.服务端返回对应探测帧:3probe(pong)

8.客户端发送polling升级为websocket:5(upgrade)

9.服务端同意发送noop消息停止polling:6(noop)

10.websocket定时心跳(2/3)&收发数据(4)

transport: ['polling'] 的时候,只会使用polling来进行通讯

transport: ['websocket'] 的时候,只会使用websocket来进行通讯

transport: ['polling', 'websocket']两者同时存在时,就会看浏览器兼容性进行选择

写在最后

socket.io进行了兼容性处理,使用起来也十分方便,不过要注意,当后端使用socket.io实现时,前端也需要使用socket.io来配合,因为需要相同的协议才能进行通讯。