Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
839 views
in Technique[技术] by (71.8m points)

javascript - Prevent Socket IO from ping timeout on inactive or not focused browser page on Chrome, firefox & Safari mobile browsers

I have a simple chat app using socket io. Very similar to the socket io chat official demo. Socket io goes to ping timeout on all mobile browsers whenever the user minimizes the page or opens another app or page gets out of foucs.

In my web app whenever, the user clicks on file input upload from their chrome/firefox/safari browser on mobile, it opens up the phone dialog box to select the file from galley to select and upload. During this time (my chat page gets out of focus due to visibility), when user is searching for a file, and after exact 30 seconds, socket io client issues ping timeout, and the person chat is disconnected.

In my application level, i am doing a reconnect if socket io goes to ping timeout for whatever reason, but that doesn't fix my problem, because if the user clicks on 1 file after 31 seconds, then that image file is not sent in chat, because socket io was timed out during that time, and it takes few seconds to reconnect, when the user's focus is back on the browser tab. So the file upload action is lost, because file is uploaded but socket io connection was on ping timeout. so when it reconnects, the selected file upload is never sent to the other connected user.

I tried detecting whenever user's page focus is out, using this code,

document.addEventListener("visibilitychange", onchange);

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

and then once page is not in focus, i used setinterval to emit my custom heartbeat event to my server code. (just to keep socket io from talking to server to keep connection alive).. This works fine for desktop browsers, But on all mobile browsers, whenever user's page is not in focus, i.e if a user minimizes the browser, opens a new app, or goto select file upload screen, socket io times out after 30 seconds or sometimes even faster then this.

My client js code:

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 
 ", 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 
 ", socket.id);
    console.log("?learing inteval beating from visiblity");
    clearInterval(beating);
  }
}

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

And my server.js code


  //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

I also tried adjusting my socket io server & client timeout configs, but that is not making any difference, after user minimise the browser page on mobile, chorme, firefox & safari, socket io client emits ping timeout after 30 seconds or so,

How can i increase this timeout, so socket io connection remains active (don't ping timeout) for longer time (as much as i want)?

Here are my server.js configs for socket io:


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
  }
);

and my socket io client configs:


 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
    });

Basically on all mobile browsers, as long as page gets out of focus, my JS code stops executing, and whenever the page focused again, JS exection resumes, looks like its not a problem with setinterval or settimeout. How can i keep executing my client JS code to keep socket io from doing ping timeout?

I also tried a similar logic using settimeout, https://codepen.io/Suhoij/pen/jAxtn

this code works in codepen on all mobile browsers, even if i minimise this page on my mobile and come back again, the timer is still executing, but the same code when i run on my app, it doesn't work in my code. Why? Is socket io pausing my all client.js code when page is not in focus? OR is my logic not correct? I also tried emitting an event from my server.js after every 2 second to all clients, but the emits stop when page is not in foucs on mobile :/

Relevant socket io issues: https://github.com/socketio/socket.io/issues/2769

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...