Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TcpClient communication with server to keep alive connection in c#?

I've this TcpClient code which works fine. It connects to perl server on linux system and receives anything that server sents to it. Works nicely.

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

However in certain conditions I'm having some problems with it:

  1. My work connection often drops connection after some idle time so I've implemented in server so when it receives PING it responds with PONG. I can send PING with UDP to server and it will respond with PONG on tcp but i would prefer built-in way into tcp client so it does send PING every 60 seconds or so. Even if UDP solution would be acceptable I have no timeout on string varReadData = Encoding.ASCII.GetString(data, 0, bytes).Trim(); so when PONG doesn't arrive my client doesn't even notice it anyway. It just keeps waiting ... which brings me to..
  2. My other problem is that at some point string varReadData = Encoding.ASCII.GetString(data, 0, bytes).Trim(); this is waiting for data all the time. When server crashes or disconnects my client i don't even notice that. I would like server to have some kind of timeout or check if connection is active. If it's not active it should try to reconnect.

What would be simplest way to fix this TcpClient ? How do i implement both way communication making sure that if server drops my connections or my net gets disconnected client will notice it and reestablish connection ?

like image 391
MadBoy Avatar asked Jun 25 '10 21:06

MadBoy


People also ask

Does TCP maintain connection?

TCP is a connection-oriented protocol, which means a connection is established and maintained until the applications at each end have finished exchanging messages.

How TCP keep alive works?

When two hosts are connected over a network via TCP/IP, TCP Keepalive Packets can be used to determine if the connection is still valid, and terminate it if needed. Most hosts that support TCP also support TCP Keepalive. Each host (or peer) periodically sends a TCP packet to its peer which solicits a response.

How long you can keep a TCP connection alive?

A TCP Keep-Alive, originally defined in Request for Comments (RFC) 1122, is an empty TCP segment intended to cause the peer to send an ACK. The default is 1800 seconds. Note: For more information about TCP keep alive, refer to the Internet Engineering Task Force (RFC 1122).

What is TcpClient C#?

The TcpClient class provides simple methods for connecting, sending, and receiving stream data over a network in synchronous blocking mode. In order for TcpClient to connect and exchange data, a TcpListener or Socket created with the TCP ProtocolType must be listening for incoming connection requests.


2 Answers

It's not Encoding.ASCII.GetString(data, 0, bytes).Trim(); that blocks forever, it's the stream.Read() If you're reading, you can't easily distinguish between the server(or any NAT gateway inbetween) dropping your connection , and the case where the server simply doesn't have anything to send you. Atleast in the case where the TCP FIN/RST packets doesn't reach your client in case of failure, or a NAT gateway silently dropping your connection.

What you can do;

  • Set a Send/ReceiveTimeout , and ping the server if a timeout occurs, or implement your own heartbeat messages over your TCP connection. Reestablish or take other actions if you don't receive a heartbeat within a reasonable time.
  • Set the TCP keepalive option, and rely on that to tell you if the server is gone. See code here.

The last point will tell you if the tcp connection fails, it won't tell you if the server has somewhat failed - e.g. if you CTRL+Z your perl server, it'll just sit there not doing anything as the tcp window closes , so you might need to implement your own heatbeat messges to cover such a case too if you need to.

like image 75
nos Avatar answered Sep 21 '22 17:09

nos


You should get rid of the UDP heartbeat attempt and put in a real TCP heartbeat. "Pinging" the server using UDP is almost meaningless.

Your protocol is also missing message framing.

Read both of those linked articles carefully (especially message framing). The protocol you're currently using does need serious revision.

like image 42
Stephen Cleary Avatar answered Sep 19 '22 17:09

Stephen Cleary