How to detect client side internet disconnection using Node.js

6.4k Views Asked by At

I am using node.js for game server .

Here is my server script

 var net = require('net');
 var http = require('http');

var host =  '192.168.1.77';
var portNum = 12345;//


  function policy() 
{
    var xml = '<?xml version="1.0"?>\n<!DOCTYPE cross-domain-policy SYSTEM' +
            '"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">\n<cross-domain-policy>\n';

    xml += '<allow-access-from domain="*" to-ports="*"/>\n';
    xml += '</cross-domain-policy>\n\0' + "\0";
    return xml;
}



var server = net.createServer(function (stream) 
{
stream.setEncoding('utf8');

stream.on('data', function (data) { 

    if (data == '<policy-file-request/>\0') 
    {
        var x = policy();
        stream.write(x);
        var server_date = new Date();
        var serv_sec = server_date.getSeconds();
        return;
    }

    var comm = JSON.parse(data); 
    if (comm.action == "Join_Request"  && comm.gameId =="game1") // join request getting from client
    {
        var reply0 = new Object();
        reply0.message = "WaitRoom";
        stream.write(JSON.stringify(reply0) + "\0");   
     }
 });

stream.on('disconnect', function() 
{
    console.log("disconnect");
 });
stream.on('close', function ()  
{
console.log("Close");
}); 

 //stream.setNoDelay(true);
//stream.setKeepAlive(true, 200);
//stream.setTimeout(10, function(){
//  console.log('timeout');
//});
 stream.on('connect', function() {
 console.log('check 2', stream.connected);
 }   );
  stream.on('error', function () { 
  console.log("Error");
  }); // close function 

  });  // ===== create server end
  server.listen(portNum,host,{'heartbeat interval':1,  'heartbeat timeout' : 2}  );

===============================================================================================

Client side script

    using UnityEngine;
    using System.Collections;
    using System;
    using System.Xml;
    using System.Linq;
    using System.Threading;
    using Boomlagoon.JSON;
    using JsonFx.Json;
    using System.Net.Sockets;

                      try 
                        {

                            tcpClient.Connect (host,portNum);
                            serverStream    =  tcpClient.GetStream ();
                            serverStream.Flush ();

                            ThreadPool.QueueUserWorkItem( new WaitCallback( ReceiveFromServer ) );



                            isConnectionActive = true;
                            isReadyToJoinRoom = true;
                            connected = 1;
                            disconnected =0;
                            c_global.isClientConnectOn = false;
                            c_global.isClientDisconnectOn = false;

                        }
                        catch( ArgumentException l_exception )
                        {
                            c_global.isClientDisconnectOn = true;
                            isConnectionActive = false;
                        }

                        catch( SocketException l_exception )
                        {
                            c_global.isClientDisconnectOn = true;
                            isConnectionActive = false;
                        }

                        catch(Exception e)
                        {
                            c_global.isClientDisconnectOn = true;
                            isConnectionActive = false;
                            connected = 0;
                            disconnected =1;

                        }


               public void ReceiveFromServer(object stateInfo) // Please call this function once
                {
                    print (" $$$$$$$$$$$ ReceiveFromServer  and isConnectionActive"+isConnectionActive);

                    while(isConnectionActive) // receive message continuously 
                    {
                        try
                        {
                            byte [] inStream = new byte[tcpClient.ReceiveBufferSize];

                            serverStream.Read (inStream,0,(int)tcpClient.ReceiveBufferSize);
                            string returnData = System.Text.Encoding.UTF8.GetString(inStream);

                            print ("*^^^^^^^^^^* returnData"+returnData);
                            Decide_Action(returnData);


                        }
                        catch (Exception e)
                        {
                            c_global.isClientDisconnectOn = true;
                        }


                    }

                }



           public void Decide_Action(string returnData)
           {
           try
           {

           var r_Msg = JSONObject.Parse(returnData); // recieved message r_Msg

           string msg = r_Msg.GetString("message") ;

           print ("Message = "+msg);

           switch(msg ) // check the action to do
           {
           case "Players_List":
           break;
           }

           }

           catch (Exception e)
           {
                            c_global.isClientDisconnectOn = true;
           }


           }

When game is close or quit from game , client disconnection detect by server . That is "close" function and "error" function is calling that time.

But when internet disconnections from client system or device , that time "close" function or "error" function is not calling.

How to detect this kind of client disconnection

Client Net disconnection is not detecting by Node.js server .

Please help me , if anyone know the solution .

4

There are 4 best solutions below

1
On

Best way is to probably handle the 'timeout' event, which is fired when there's too much inactivity. You can set how long you want that to be as well, though there's a reasonable default.

http://nodejs.org/api/net.html#net_event_timeout

6
On

It isn't possible to differentiate a lost connection from an idle connection.

At least, not directly without some modification...

TCP connections are designed to live even if no data is sent. It is entirely possible to make a connection now, send nothing for 12 hours, and send data again later. Should the server assume that the connection is no longer there? By design, it will assume there is a connection unless there is a transmission failure. That is, if data is sent and there is no ACK, the connection will eventually be closed and the appropriate events will fire.

The solution is to use TCP keepalive. If you call socket.setKeepAlive(true, 10000), you enable keepalive probe packets (effectively TCP packets with 0 bytes of data payload) to be sent on an idle socket 10 seconds after it becomes idle. The remote system will ACK these packets. If it does not, the connection is eventually assumed lost, and the events you're looking for will fire.

More information:

0
On

There is (currently) no disconnect event defined to be emitted from net.Server nor net.Socket. There is an end event, fired from net.Socket when a FIN packet is received. When keepalive is used, timeout will be triggered if there is no ACK from the other end within the defined timeout (also note that the socket is not automatically closed in this case).

1
On

This is an old post, but since I am new to posting on stackoverflow I thought that I could practice on this question. So here goes:

A common solution is to have the client sending an explicit keep-alive message (application layer instead of a transport layer) to the server whenever the connection is idle. The server can then identify connection (and client health) problems by adding an idle timeout.

In short: You need an idle timer in the server to detect if the connection is lost. And you need an idle timer in the client to ensure that you send a keep-alive message whenever the connection is idle.

Server pseudo code:

const SERVER_TIMEOUT = 3000;
var idle;

function clientFailed() {
    // Client has failed or the connection is bad
}

function onClientConnect() {
    // Start connection health monitoring
    idle = setTimeout(clientFailed, SERVER_TIMEOUT);
}

function onClientSendOrReceive() {
    // make sure that the old timer does not trigger
    clearTimeout(idle);
    // Start a new idle timeout
    idle = setTimeout(clientFailed, SERVER_TIMEOUT);
}

Client side pseudo code:

const CLIENT_TIMEOUT = 2000;  // Should be less than the server timeout to account for normal network latency
var idle;

function sendKeepalive() {
    // Send keepalive message to server
}

function onConnectToServer() {
    // Start idle timer
    idle = setTimeout(sendKeepalive, CLIENT_TIMEOUT);
}

function onSendOrReceiveMessage() {
    // make sure that the old timer does not trigger
    clearTimeout(idle);
    // Start a new idle timeout
    idle = setTimeout(sendKeepalive, CLIENT_TIMEOUT);
}