0

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


           }

当游戏关闭或退出游戏时,服务器会检测客户端断开连接。那是“关闭”功能和“错误”功能正在调用那个时间。

但是当与客户端系统或设备断开互联网连接时,那个时候“关闭”功能或“错误”功能不会被调用。

如何检测这种客户端断开连接

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

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

4

4 回答 4

8

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

至少,不是直接没有一些修改......

TCP 连接被设计为即使没有发送数据也能存活。现在完全可以建立连接,12小时内什么都不发送,稍后再发送数据。服务器是否应该假设连接不再存在?按照设计,除非传输失败,否则它将假定存在连接。也就是说,如果发送了数据并且没有 ACK,则连接最终将被关闭并触发相应的事件

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

更多信息:

于 2014-12-09T05:29:11.187 回答
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);
}
于 2016-09-14T12:03:01.527 回答
0

最好的方法可能是处理“超时”事件,当有太多不活动时会触发该事件。尽管有一个合理的默认值,但您也可以设置希望的时间长度。

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

于 2014-12-09T05:20:02.633 回答
0

(当前)没有disconnect定义为从net.Servernor发出的事件net.Socket。有一个end事件,从收到数据包net.Socket时触发。FIN当使用keepalivetimeout时,如果在定义的超时时间内没有来自另一端,将被触发ACK(还要注意这种情况下套接字不会自动关闭)。

于 2017-09-20T16:13:25.093 回答