2010-06-25 28 views
3

我有這個TcpClient的代碼工作正常。它連接到Linux系統上的perl服務器並接收任何服務器向其發送的消息。很好地工作。TcpClient與服務器通信保持在C#中的連接活動?

  1. 我的工作有關的常滴一些空閒時間,所以我一直在服務器實現的,所以當它接收PING它響應後連接:

    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)); 
         } 
        } 
    
    在我有與它的一些問題,一定條件下

    然而與PONG。我可以使用UDP發送PING到服務器,並且它會在tcp上響應PONG,但我更喜歡內置到tcp客戶端的方式,因此它每隔60秒左右發送一次PING。即使UDP解決方案可以接受,我也沒有在string varReadData = Encoding.ASCII.GetString(data, 0, bytes).Trim();上超時,所以當PONG沒有到達時,我的客戶無論如何都沒有注意到它。它只是一直在等待...這使我想..

  2. 我的其他問題是,在某個點string varReadData = Encoding.ASCII.GetString(data, 0, bytes).Trim();這是一直在等待數據。當服務器崩潰或斷開我的客戶,我甚至沒有注意到。我想要服務器有某種timeout或檢查連接是否處於活動狀態。如果它不活動,它應該嘗試重新連接。

什麼是最簡單的方法來解決這個TcpClient?我如何實現雙向通信,確保服務器斷開我的連接或我的網絡斷開連接的客戶端會注意到它並重新建立連接?

回答

4

這不是Encoding.ASCII.GetString(data, 0, bytes).Trim();阻止永遠,這是stream.Read() 如果你讀,你不能輕易的服務器(或其間的任何NAT網關)下降的連接,並在服務器只是沒有按」的情況下區分沒有任何東西可以寄給你。至少在發生故障時TCP FIN/RST數據包未到達客戶端的情況下,或者NAT網關無聲地丟棄連接。

你可以做什麼;

  • 設置Send/ReceiveTimeout,如果發生超時,請ping服務器,或通過TCP連接實現自己的心跳消息。如果在合理的時間內沒有收到心跳,請重新建立或採取其他措施。
  • 設置TCP keepalive選項,並依靠它來告訴你服務器是否消失。請參閱代碼here

最後一點會告訴你tcp連接是否失敗,它不會告訴你服務器是否有些失敗 - 例如,如果你CTRL + Z你的perl服務器,它只會坐在那裏,因爲tcp窗口關閉時不會做任何事情,所以如果你需要的話,你可能需要實現自己的heatbeat消息來覆蓋這種情況。

+0

那麼這就是我想要的......有我自己的心跳在TCP上,只是我不知道如何做到這一點。將測試ReceiveTimeout如何工作,看看它是否工作,因爲我認爲它的確如此。如果它流了。讀取()放手,當沒有數據收到後,讓我們說50秒,然後我可以添加「發送消息PING」在代碼中,因爲服務器已經在等待。如果它收到PING,它會發送PONG,所以我會知道它是否工作。 – MadBoy 2010-06-26 17:18:29

+0

'ReceiveTimeout'唯一的問題是它會拋出異常並丟棄連接,所以我將不得不使新的能夠發送心跳。 – MadBoy 2010-06-26 21:37:44

2

你應該擺脫UDP心跳嘗試並將其放入real TCP heartbeat。使用UDP「ping」服務器幾乎沒有意義。

您的協議也丟失message framing

仔細閱讀這些鏈接的文章(尤其是消息框架)。您目前使用的協議確實需要嚴格的修訂。

+0

通過ping服務器我的意思是我有perl中的TCP/UDP服務器。它監聽UDP和TCP。所以我可以將PING值發送給UDP,並且TCP服務器在UDP上看到PING可以使用PONG返回TCP,這將保持連接運行。然而,你是對的,它不是現在的最好的實現。 – MadBoy 2010-06-27 16:09:08

相關問題