如何使用Node.js检测客户端Internet断开连接

时间:2014-12-08 11:25:25

标签: node.js disconnect node.js-stream

我正在将node.js用于游戏服务器。

这是我的服务器脚本

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

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

客户端脚本

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


           }

当游戏关闭或退出游戏时,客户端断开连接会被服务器检测到。那是&#34;关闭&#34;功能和&#34;错误&#34;函数正在调用那个时间。

但是当互联网与客户端系统或设备断开连接时,那个时间&#34;关闭&#34;功能或&#34;错误&#34;功能不是在呼唤。

如何检测此类客户端断开连接

Node.js服务器未检测到客户端网络断开连接。

如果有人知道解决方案,请帮帮我。

4 个答案:

答案 0 :(得分:7)

无法区分丢失的连接和空闲连接。

至少,不是没有经过一些修改......

即使没有数据发送,TCP连接也可以存活。完全可以立即建立连接,12小时不发送任何内容,稍后再发送数据。服务器应该假设连接不再存在吗?根据设计,除非存在传输故障,否则它将假定存在连接。也就是说,如果发送数据且没有ACK,则最终将关闭连接,并且触发相应的事件。

解决方案是使用TCP keepalive。如果您调用socket.setKeepAlive(true, 10000),则启用keepalive探测数据包(实际上是具有0字节数据负载的TCP数据包)在空闲套接字上发送它变空后10秒钟。远程系统将确认这些数据包。如果没有,最终会假设连接丢失,并且您正在寻找的事件将被触发。

更多信息:

答案 1 :(得分:1)

这是一篇旧帖子,但由于我刚接触stackoverflow,我认为我可以练习这个问题。所以这里:

常见的解决方案是让客户端在连接空闲时向服务器发送显式保持活动消息(应用程序层而不是传输层)。然后,服务器可以通过添加空闲超时来识别连接(和客户端运行状况)问题。

简而言之:您需要服务器中的空闲计时器来检测连接是否丢失。并且您需要在客户端中使用空闲计时器,以确保在连接空闲时发送保持活动消息。

服务器伪代码:

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

客户端伪代码:

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

答案 2 :(得分:0)

最好的方法是处理'超时'事件,当有太多不活动时会触发该事件。你也可以设定你想要多长时间,尽管有一个合理的默认值。

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

答案 3 :(得分:0)

(目前)没有disconnect事件被定义为从net.Servernet.Socket发出。当收到FIN数据包时,end event会发出net.Socket。使用keepalive时,如果在定义的超时内没有来自另一端的timeout,则会触发ACK(同时请注意套接字>在这种情况下关闭)。