【问题标题】:Prevent Socket IO from ping timeout on inactive or not focused browser page on Chrome, firefox & Safari mobile browsers防止 Socket IO 在 Chrome、firefox 和 Safari 移动浏览器上的非活动或未集中浏览器页面上 ping 超时
【发布时间】:2022-03-17 04:46:13
【问题描述】:

我有一个使用套接字 io 的简单 chat 应用程序。非常类似于socket io chat官方demo。每当用户最小化页面或打开另一个应用程序或页面失控时,Socket io 都会在所有移动浏览器上进行 ping 超时。

在我的网络应用程序中,每当用户从移动设备上的 chrome/firefox/safari 浏览器单击文件输入上传时,它会打开手机对话框以从厨房中选择文件以进行选择和上传。在此期间(我的聊天页面由于可见性而失去焦点),当用户搜索文件时,恰好 30 秒后,套接字 io 客户端发出 ping 超时,并且人员聊天断开连接。

在我的应用程序级别,如果套接字 io 出于某种原因进入 ping 超时,我正在重新连接,但这并不能解决我的问题,因为如果用户在 31 秒后单击 1 个文件,则该图像文件是未在聊天中发送,因为在此期间套接字 io 超时,并且当用户的焦点重新回到浏览器选项卡上时,重新连接需要几秒钟。因此文件上传操作丢失,因为文件已上传但套接字 io 连接在 ping 超时。所以当它重新连接时,选择的文件上传永远不会发送给其他连接的用户。

我尝试使用此代码检测用户的页面焦点何时消失,

document.addEventListener("visibilitychange", onchange);

来自Is there a way to detect if a browser window is not currently active?

然后一旦页面不在焦点上,我使用 setinterval 将我的自定义心跳事件发送到我的服务器代码。 (只是为了防止套接字 io 与服务器通信以保持连接处于活动状态).. 这适用于桌面浏览器,但在所有移动浏览器上,只要用户的页面不在焦点上,即如果用户最小化浏览器,就会打开一个新应用程序,或转到选择文件上传屏幕,socket io 在 30 秒后超时,有时甚至更快。

我的客户端js代码:

var beating;
//function to detect if user gone out of page

//startSimulation and pauseSimulation defined elsewhere
function handleVisibilityChange() {
  //socket = this.socket;
  if (document.hidden) {
    // console.log();
    $('#logwrapper').prepend(" üser is outside \n ", socket.id);

    //emit on server after every 10 seconds
    beating = setInterval(function () {
      $('#logwrapper').prepend(" inside interval emitting");

      socket.emit('heartbeat', { data: "a" });
    }, 15000)

  } else {
    //console.log("üser is in");
    $('#logwrapper').prepend(" üser is in \n ", socket.id);
    console.log("çlearing inteval beating from visiblity");
    clearInterval(beating);
  }
}

document.addEventListener("visibilitychange", handleVisibilityChange, false);

还有我的 server.js 代码


  //socket events for heartbeat 
    socket.on("heartbeat", function (data) {
      console.log("socket is outside ", data, socket.id);
    });
    //socket events for heartbeat , just log it so that my client remains active and keep communicating with server, to avoid socket io timeout

我还尝试调整我的套接字 io 服务器和客户端超时配置,但这没有任何区别,在用户最小化移动设备、chorme、firefox 和 safari 上的浏览​​器页面后,套接字 io 客户端在 30 秒左右后发出 ping 超时,

如何增加此超时时间,以便套接字 io 连接保持活动状态(不要 ping 超时)更长的时间(我想要的时间)?

这是我的 socket io 的 server.js 配置:


var io = require("socket.io")(
  231, {
    transports: ["websocket", "polling"]
  },
  server, {
    path: '/socket.io',
    serveClient: true,
    // below are engine.IO options
    pingInterval: 25000, //was 10k, how many ms before sending a new ping packet, => how often to send a ping
    pingTimeout: 30000, //should be above 30k to fix disconnection issue how many ms without a pong packet to consider the connection closed
    upgradeTimeout: 20000, // default value is 10000ms, try changing it to 20k or more
    agent: false,
    cookie: false,
    rejectUnauthorized: false,
    reconnectionDelay: 1000,
    reconnectionDelayMax: 5000,
    maxHttpBufferSize: 100000000 //100 mb
  }
);

和我的套接字 io 客户端配置:


 this.socket = io.connect('https://appurl.com', {
      reconnection: true,
      reconnectionDelay: 1000,
      reconnectionDelayMax: 5000,
      reconnectionAttempts: Infinity,
      //our site options
      transports: ["polling", "websocket"],
      secure: true,
      rejectUnauthorized: false,
      forceNew: false,
      timeout: 60000
    });

基本上在所有移动浏览器上,只要页面失焦,我的 JS 代码就会停止执行,并且每当页面再次聚焦时,JS 执行就会恢复,看起来它不是 setinterval 或 settimeout 的问题。如何继续执行我的客户端 JS 代码以防止套接字 io 执行 ping 超时?

我也尝试过使用 settimeout 的类似逻辑,https://codepen.io/Suhoij/pen/jAxtn

此代码适用于所有移动浏览器的 codepen,即使我在移动设备上最小化此页面并再次返回,计时器仍在执行,但是当我在我的应用程序上运行相同的代码时,它不起作用我的代码。为什么?当页面不在焦点时,socket io 是否会暂停我的所有 client.js 代码?或者我的逻辑不正确?我还尝试在每 2 秒后从我的 server.js 向所有客户端发出一个事件,但是当页面不在移动设备上时发出停止:/

相关的socket io问题: https://github.com/socketio/socket.io/issues/2769

【问题讨论】:

  • 移动浏览器非常积极地尝试在有任何东西离开前台时节省电池电量。否则,你会得到十几个应用程序都使用一点电池,突然电池寿命是它可能的一半。常规应用(不是浏览器页面)可以选择使用本地平台推送支持,这可能限制较少。
  • @jfriend00 所以你给我的建议是为 iOS 和 Android 制作原生应用程序以避免这个问题?所以即使页面进入后台,也没有办法强制这种行为保持套接字 io 处于活动状态?也许套接字 io 配置中的某些内容可以帮助我将此超时的持续时间增加到 1 分钟而不是 30 秒?
  • 我不知道在浏览器页面中解决此问题的最佳方法。我只知道移动浏览器已经打击了在后台页面中使用电池的任何内容。浏览器中的 socket.io 只是位于原生 webSocket 和 Ajax 支持之上的 Javascript,因此除了常规浏览器编程之外,它没有任何保持活力的能力。它不能破坏移动浏览器强制执行的任何规则。如果您想在网页中执行此操作,我建议您找到其他一些执行此类操作的网络应用程序并查看网页代码以了解它们是如何执行的。
  • @Faizan 我也遇到了同样的问题!你解决了吗?如果是,请给我一些提示
  • @basilisk 如果您检查我的答案,它可能会有所帮助

标签: javascript node.js google-chrome socket.io settimeout


【解决方案1】:

对于我必须在 socket.io 4.4.1 上做的事情

我使用管理器事件来处理移动设备上的断开连接 https://socket.io/docs/v4/client-api/#event-error

    import io from "socket.io-client";
    socket = io(socketUrl, {
        reconnectionAttempts,
        reconnectionDelay,
    });

    //for the actual websocket having an error attempt to reconnect
    socket.io.on("error", (error) => {
        // ...
        console.log('socket io error on ' + error);
        socket = io(socketUrl, {
            reconnectionAttempts,
            reconnectionDelay,
        });
    });

    let socketArray = ['reconnect', 'reconnect_attempt', 'reconnect_error', 'reconnect_failed'];

    for(let i = 0, len = socketArray.length; i < len; i++) {
        socket.io.on(socketArray[i], (attempt) => {
            // ...
            console.log(socketArray[i] + ' socket io on ' + attempt);
        });
    }

如果 websocket 管理器出现错误,它将重新连接。当我在套接字上的浏览器中正常时,我发生了这种情况,关闭我的 iPhone,回到浏览器并使用 socket.on('connection' 重新连接,然后当我再次关闭我的手机屏幕然后重新进入时,我会通过添加socket.io.on("error" 得到这个错误WebSocket connection to 'wss://mysocketserver.com' failed: The operation couldn’t be completed. (kNWErrorDomainPOSIX error 53 - Software caused connection abort) 并让它重新连接它会正确地重新建立一切

【讨论】:

    猜你喜欢
    • 2011-02-18
    • 1970-01-01
    • 2018-10-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-19
    • 1970-01-01
    • 2016-05-14
    • 1970-01-01
    相关资源
    最近更新 更多