TcpClient与服务器通信以保持c#中的活动连接?

时间:2010-06-25 21:34:44

标签: c# .net-4.0 tcpclient

我有这个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响应,但我更喜欢内置的方式进入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或检查连接是否有效。如果它不活动,它应该尝试重新连接。
  3. 修复此TcpClient最简单的方法是什么?我如何实现双向通信,确保如果服务器丢失我的连接或我的网络断开客户端将注意到它并重新建立连接?

2 个答案:

答案 0 :(得分:5)

Encoding.ASCII.GetString(data, 0, bytes).Trim();永远不会阻挡,stream.Read() 如果您正在阅读,则无法轻易区分丢弃连接的服务器(或其间的任何NAT网关),以及服务器根本没有任何内容可以发送给您的情况。如果TCP FIN / RST数据包在发生故障时无法到达您的客户端,或者NAT网关静默地断开您的连接,则为Atleast。

你可以做什么;

  • 设置发送/ ReceiveTimeout,如果发生超时则ping服务器,或通过TCP连接实现自己的心跳消息。如果您在合理的时间内没有收到心跳,请重新建立或采取其他措施。
  • 设置TCP keepalive选项,并依赖它来告诉您服务器是否已经消失。请参阅代码here

最后一点将告诉您tcp连接是否失败,它不会告诉您服务器是否有一些失败 - 例如如果你用CTRL + Z你的perl服务器,它就会在tcp窗口关闭的情况下不做任何事情,所以如果你需要,你可能需要实现自己的热量消息来覆盖这样的情况。

答案 1 :(得分:2)

您应该摆脱UDP心跳尝试并输入real TCP heartbeat。使用UDP“ping”服务器几乎没有意义。

您的协议也缺失message framing

仔细阅读这些链接文章(特别是邮件框架)。您当前使用的协议确实需要严格修改。