我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

众所知之的是:socket.io并不是一个协议的名词,它是一个兼容性质的框架。它的底层协议,不仅包括websocket,还包括其它"polling"/"flashsocket"/"xhr-polling"/"jsonp-polling"/"iframe streaming"等其它技术手段。在最新的v4socket.io中,transports的默认值有两个,分别是:websocketpolling

苏南大叔:Socket.io双向通信教程,如何修改底层协议信息 - socket
Socket.io双向通信教程,如何修改底层协议信息(图5-1)

苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。测试环境:win10nodejs@20.18.0express@4.21.2socket.io@4.8.1。本文讲解socket.io的底层协议切换相关事项。

前文回顾

socket.io的基础使用例子:

socket.io的路径相关设置:

服务端基础代码:

//...
const socketio = require("socket.io");
const io = socketio(expressServer,{
    serveClient: false,    // 是否控制客户端文件
    path:"/.io/",          // 客户端所有请求路径,注意和客户端设定保持一致
});
//...

客户端基础代码:

<script>
const socket = io(
  "https://localhost:82",   // 一定概率下,会出现跨域问题
  { path:'/.io/' }          // 注意和服务端的path设定保持一致
);
// ...
</script>

参数 transports

注意这个单词的拼写是复数带s,和上一篇文章里面的path参数,放在同一个位置。主要表明支持什么样的底层协议。所以,客户端设置也可以,服务端设置也可以。两者是协商的关系,当然如果协商不一致,就以客户端的为“错误”请求为主么,毕竟还是客户端占有主动性。

服务端和客户端,两者【协商】的结果。协商的标准很多,并不仅仅是简单的取transports的交集,就可以强制使用某个底层协议,还存在着其它的因素。但是,如果双方都设置成仅仅支持某一种协议。那么,大概率情况下,协商的结果就是它了。

设置为只polling

轮询实际上是以http协议为主的,客户端定期向服务端发起请求,以检测是否存在消息。
服务端:

const socketio = require("socket.io");
const io = socketio(expressServer,{
  transports: ['polling'] // 只允许轮询
});

最好同时设置客户端:

const socket = io({
  transports:["polling"],  // 只允许轮询
  // upgrade: false,
});

苏南大叔:Socket.io双向通信教程,如何修改底层协议信息 - socket
Socket.io双向通信教程,如何修改底层协议信息(图5-2)

设置为只 websocket

目前来说,默认大多数情况下,都是会使用websocket的。但是,也可以在服务器端或者客户端设置为只支持websocket

服务端:

const socketio = require("socket.io");
const io = socketio(expressServer,{
  transports: ['websocket'] // 只允许websocket
});

最好同时设置客户端:

const socket = io({
  transports:["websocket"]  // 只允许websocket
});

苏南大叔:Socket.io双向通信教程,如何修改底层协议信息 - socket
Socket.io双向通信教程,如何修改底层协议信息(图5-3)

默认参数

如果保持transports参数默认的话,也可能会出现
四个(有且仅有)看起来非常“轮询”的请求,如下图所示。并且部分服务器端消息,就可能由polling请求传递回来的。如下图所示:

苏南大叔:Socket.io双向通信教程,如何修改底层协议信息 - 默认典型场景
Socket.io双向通信教程,如何修改底层协议信息(图5-4)

包括其中的websocket的一个请求,一共五个请求。它们的作用分别是:

  1. Engine.IO 握手(包含会话 ID — 此处 zBjrh...AAAK — 用于后续请求)
  2. tSocket.IO 握手请求(包含auth选项的值)
  3. Socket.IO 握手响应(包含Socket#id
  4. WebSocket 连接
  5. 第一个 HTTP 长轮询请求,一旦建立 WebSocket 连接就关闭。

代码判断当前协议

其实从f12抓包的结果上,很容易就能判断当前的基础底层协议是啥。但是如果代码有办法进行判断的话,也是不错的选择。对吧。

服务端判断代码:

const io = socketio(expressServer, {});
io.on("connection", (socket) => {
    const transport = socket.conn.transport.name; // in most cases, "polling"
    console.log(transport);
    socket.conn.on("upgrade", () => {
        const upgradedTransport = socket.conn.transport.name; // in most cases, "websocket"
        console.log("升级为:",upgradedTransport);
    });
    //...
});

客户端判断代码:

const socket = io({});
socket.on("connect", () => {
  const transport = socket.io.engine.transport.name; // 在大多数情况下, "polling"
  console.log(transport);
  socket.io.engine.on("upgrade", () => {
    const upgradedTransport = socket.io.engine.transport.name; // 在大多数情况下, "websocket"
    console.log("升级为:",upgradedTransport);
  });
});
//...

苏南大叔:Socket.io双向通信教程,如何修改底层协议信息 - 判断底层协议
Socket.io双向通信教程,如何修改底层协议信息(图5-5)

题外话

所以,如果想抓别人的socket.io数据的话,最好的办法就是:自己的代码仅仅支持websocket!然后直接连对方的ws://或者wss://接口。直接减少复杂度!

结论

结论就是:服务端和客户端都可以通过transports参数,声明自己仅支持的底层协议,以影响最终的协商结果。不管协商结果如何,开始的这几个非常类似polling请求的握手请求,也是不可避免的。

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   socket