5

私は正常に動作するこのTcpClientコードを持っています。Linuxシステム上のperlサーバーに接続し、サーバーが送信したものをすべて受信します。うまく動作します。

 public static void Main() {
         foreach (ProtocolConnection tcpConnection in TcpConnectionsList) {
                ProtocolConnection connection = tcpConnection;
                ThreadPool.QueueUserWorkItem(_ => {
                                                 ThreadTcpClient(connection);
                                                 ManualResetEventTcp.Set();
                                             });
         }
         ... Some code...      
 }

 public static void TcpConnect(ProtocolConnection varConnection) {
        int retryCountSeconds = varConnection.RetryEverySeconds*Program.MilisecondsMultiplier;
        int count = 0;
        while (true) {

            try {
                using (var client = new TcpClient(varConnection.IpAddress.ToString(), varConnection.Port) { NoDelay = true })
                using (var stream = client.GetStream()) {
                    var data = new Byte[256];
                    while (!Program.PrepareExit) {
                        Int32 bytes = stream.Read(data, 0, data.Length);
                        string varReadData = Encoding.ASCII.GetString(data, 0, bytes).Trim();
                        if (varReadData != "" && varReadData != "PONG") {
                            VerificationQueue.EnqueueData(varReadData);
                            Logging.AddToLog("[TCP][" + varConnection.Name + "][DATA ARRIVED]" + varReadData);
                        } else {
                            Logging.AddToLog("[TCP]" + varReadData);
                        }
                    }
                }
            } catch (Exception e) {
                if (e.ToString().Contains("No connection could be made because the target machine actively refused it")) {
                    Logging.AddToLog("[TCP][ERROR] Can't connect to server (" + varConnection.Name + ") " + varConnection.IpAddress + ":" + varConnection.Port );
                } else {
                    Logging.AddToLog(e.ToString());
                }

            }
            DateTime startTimeFunction = DateTime.Now;
            do {
                Thread.Sleep(1000);
            } while (((DateTime.Now - startTimeFunction).TotalSeconds < retryCountSeconds));
        }
    }

ただし、特定の条件では、いくつかの問題が発生しています。

  1. 私の仕事用接続はアイドル時間の後に接続を切断することが多いので、サーバーに実装したので、PINGを受信するとPONGで応答します。UDPを使用してPINGをサーバーに送信でき、tcpでPONGで応答しますが、60秒ごとにPINGを送信するように、tcpクライアントに組み込まれた方法を使用することをお勧めします。UDPソリューションが受け入れられるとしても、タイムアウトはstring varReadData = Encoding.ASCII.GetString(data, 0, bytes).Trim();発生しないため、PONGが到着しない場合、クライアントはとにかくそれに気づきません。それはただ待ち続けます...それは私を連れて来ます..
  2. 私の他の問題は、ある時点でstring varReadData = Encoding.ASCII.GetString(data, 0, bytes).Trim();これが常にデータを待機していることです。サーバーがクラッシュしたり、クライアントを切断したりしても、気づきません。サーバーに何らかの機能を持たせtimeoutたり、接続がアクティブかどうかを確認したりしたいのですが。アクティブでない場合は、再接続を試みる必要があります。

このTcpClientを修正する最も簡単な方法は何でしょうか?サーバーが接続を切断したり、ネットが切断されたりした場合にクライアントがそれに気づき、接続を再確立することを確認するために、双方向通信を実装するにはどうすればよいですか?

4

2 に答える 2

7

それはEncoding.ASCII.GetString(data, 0, bytes).Trim();永遠にブロックされるわけで stream.Read() はありません。読んでいると、接続を切断しているサーバー(またはその間のNATゲートウェイ)と、サーバーに送信するものがない場合を簡単に区別できません。少なくとも、障害が発生した場合にTCP FIN / RSTパケットがクライアントに到達しない場合、またはNATゲートウェイがサイレントに接続を切断する場合。

あなたができること;

  • Send / ReceiveTimeoutを設定し、タイムアウトが発生した場合はサーバーにpingを実行するか、TCP接続を介して独自のハートビートメッセージを実装します。妥当な時間内にハートビートが受信されない場合は、再確立するか、他のアクションを実行してください。
  • TCPキープアライブオプションを設定し、それに依存してサーバーがなくなったかどうかを通知します。ここのコードを参照してください。

最後のポイントは、tcp接続が失敗したかどうかを示し、サーバーがいくらか失敗したかどうかは示しません。たとえば、perlサーバーをCTRL + Zすると、tcpウィンドウが閉じても何もせずにそのままになります。したがって、必要に応じて、このような場合もカバーするために、独自のヒートビートメッセージを実装する必要がある場合があります。

于 2010-06-25T22:29:09.303 に答える
3

UDPハートビートの試行を取り除き、実際のTCPハートビートを挿入する必要があります。UDPを使用してサーバーに「ping」することはほとんど意味がありません。

プロトコルにもメッセージフレーミングがありません。

これらのリンクされた記事の両方を注意深く読んでください(特にメッセージフレーミング)。現在使用しているプロトコルは、大幅な改訂が必要です。

于 2010-06-26T03:22:16.213 に答える