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


           }

ゲームを閉じるか、ゲームを終了すると、クライアントの切断がサーバーによって検出されます。それが「close」関数であり、「error」関数がその時に呼び出しています。

ただし、クライアント システムまたはデバイスからインターネットが切断された場合、その時点で「閉じる」関数または「エラー」関数は呼び出されません。

この種のクライアント切断を検出する方法

Client Net 切断が Node.js サーバーによって検出されません。

誰かが解決策を知っているなら、私を助けてください。

4

4 に答える 4

8

失われた接続とアイドル状態の接続を区別することはできません。

少なくとも、何らかの変更なしで直接ではありません...

TCP 接続は、データが送信されなくても存続するように設計されています。今すぐ接続して、12 時間何も送信せず、後でもう一度データを送信することは完全に可能です。サーバーは、接続が存在しないと想定する必要がありますか? 設計上、伝送障害がない限り、接続があると見なされます。つまり、データが送信され、ACK がない場合、接続は最終的に閉じられ、適切なイベント発生します。

解決策は、TCP キープアライブを使用することです。 を呼び出すとsocket.setKeepAlive(true, 10000)、キープアライブ プローブ パケット (事実上、データ ペイロードが 0 バイトの TCP パケット) が、アイドル状態になってから 10 秒後にアイドル ソケットで送信されるようになります。リモート システムは、これらのパケットに ACK を返します。そうでない場合、接続は最終的に失われたと見なされ、探しているイベントが発生します。

詳しくは:

于 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 に答える