Skip to content

socketio #261

Open
Open
@yaofly2012

Description

@yaofly2012

Socket.IO

Socket.IO的能力

image

实现Socket.IO服务器和Socket.IO客户端之间双向通讯。基于websocket技术实现,并以HTTP长轮询(HTTP long-polling, 简称polling)作为兜底方案。

Socket.IO不是WebScoket的实现

Socket.IO不是WebScoket的实现!
Socket.IO不是WebScoket的实现!
Socket.IO不是WebScoket的实现!
重要的事情说三遍~~~
socket.io本质是一个实现双向通讯的库,只是在实现上依赖了websocket技术。弄清楚这一点很重要,明白这个就会更好的理解Socket.IO一些行为。

代码结构

image

Socket.IO客户端和服务端分别是两个库,并且各自又分为两层:

  1. socket.io-clientsocket.io提供顶层的API,供外部直接使用。
  2. Engine.IO则负责底层的连接管理,如:传输方式,升级机制,离线检测等。让上层API不用关注数据是如何传输的。

传输方式(transports)

  1. HTTP长轮询
  2. WebSocket

既然websocket是实现双向通讯的最佳方案,那为啥Socket.IO默认采用HTTP长轮询?
Socket.IO-client代码片段

_this.transports = opts.transports || ["polling", "websocket"];

理想很丰富,现实很骨感。websocket服务总是不可用?
Engine.IO 首先关注可靠性和用户体验,其次是潜在的用户体验改进和提高服务器性能。

Polling工作机制

客户端定时发起轮询,一个轮询包含一个GET请和一个POST请求:

  1. GET请求是为了获取服务端数据(模拟服务端向客户端“推送”数据)
  2. POST请求是把客户端数据传给服务端。

websocket工作机制

客户端请求query string

客户群请求时会拼接用户自定义的query string,还有一些内置的query string:

  1. EIO: EIO是Engine.IO缩写,表示Engine.IO的版本
  2. transport: 当前采用的传输类型
  3. t:时间戳hash
  4. sid: SessionId。在握手时由服务端生成,客户端后续请求都必须带上。

image

升级机制(Upgrade)

为什么要升级?

Socket.IO优先采用HTTP长轮询实现双向通讯,但毕竟webscoket技术双向通讯的最佳方案。条件合适时Socket.IO便升级采用websocket技术传输。

什么情况下会触发升级?

  1. 客户和服务端都支持webscoket协议(由客户端发起握手请求诊断)
  2. 客户端和服务端都确保传出缓冲区为空(即没有待通过HTTP方式传输的数据)

升级过程

image

这个过程涉及两个“握手”:

  1. 第一个是Socket.IO里的概念,即Engne.IO建立连接的第一个HTTP请求。
  2. 第二个是webscoket里的概念,即请求升级协议的HTTP请求。

离线检测(心跳检测)

由服务端发起。
当采用Polling传输时怎么进行心跳检测的?只针对websocket方式么?毕竟Polling方式本身就是一种心跳检测。

服务端

概念:

image

  1. Server instance
  2. Socket instance:
    一个Service instace管理多个socket instance?
  3. engine
  4. namespace
  5. room
  6. handshake
  7. packet
  8. middleware
  9. sticky-session

namespace和room用了组织sockets?

Server instance

表示Socket服务。

import { Server } from "socket.io";

const io = new Server({ /* options */ });

Server和Namespcae什么关系啊,他们具有许多相同方法和事件。

Namespaces(命名空间)

Socket instance

负责和客户端进行交互,即通信

  1. 监听事件,on, once
  2. 向客户端发消息emit
  3. 加入,离开room?

中间件

什么时候执行
客户端向服务端发送消息时?【不是】
中间件执行的时候连接还未建立

一个连接只执行一次
连接一致活着不用多次执行。这个跟Express等HTTP服务中间件不同。

客户端

每个WebSocket客户端是一个socket实例(Socket服务端对应着多个socket实例),并且每个socket实例都归属一个命名空间,默认是/

WebSocket客户端一般有三个主要操作:

  1. 主动向Socket服务请求连接;
  2. 想Socket服务器发消息;
  3. 监听事件。

概念:

  1. Socket instance
  2. Manager, Manager instance
  3. long-polling
  4. ping

生命周期

image

三大角色

image

  1. Socket实例:
    客户端JS直接操作的API,负责和服务交互。和服务的建立连接则依赖Manager实例。
  2. Manager实例
    管理Engine.IO客户端实例,主要负责重新连接的逻辑。一个Manager实例被多个Socket实例复用(多路复用)。
  3. Engine.IO

Socket实例

var socket = io();
  1. 默认Socket服务地址是当前域名+/socket.io/
  2. 默认会自动连接服务器。
  3. 每次刷新页面socket实例id都会发生变化,即之前的会被disconnect,而重新建立连接。

注意:

  1. 虽然执行io()返回的是socket实例,但是这个函数其实会创建一个新的Mananger实例。

事件(events)

Socket继承EventEmitter,可以采用相关API进行发送,监听事件。

如何绑定事件

  1. 虽然运行在浏览器里,但是绑定事件方式跟DOM不一样哦。
    DOM继承自EventTarget),Socket继承EventEmitter,即同Nodejs环境绑定方式。
  2. 不要在connect回调函数里绑定其他事件。
    因为Socket可能会断开连接,并自动重新建立连接。这会导致重复帮忙事件。

事件类型

  1. 内置事件,即Socket内置占用的事件,如connect, disconnect等;
  2. 自定义事件,即非内置事件。

connect

disconnect

  1. 当已存在连接断开后会触发disconnect事件。注意未建立连接前的断开不会触发改事件。
  2. 当主动(即socket客户端或者socket服务端调用disconnect方法)断开连接时socket instance不会自动出发重连。

参考

  1. Everything you need to know about Socket.IO

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions