Search code examples
c#.netasynchronoustcpclientfreeze

TCP client connection freezes program


I'd like to have an asynchronous continuous ping request on a ip + port. The problem is, when the targeted server is offline, the whole program freezes during request time. But this shouldn't happen.

This is my ping function which is called once when starting the program. It should do a ping request every 3 seconds.

    public async void Start(string ip)
    {
        Stopwatch watch = new Stopwatch();

        while (true)
        {
            watch.Restart();
            using (TcpClient tcp = new TcpClient())
            {
                //try to connect to a closed port
                IAsyncResult res = tcp.ConnectAsync("127.0.0.1", 1234);

                //during the following while-loop the whole program freezes
                //although this is an asynchronous function
                while (watch.ElapsedMilliseconds < 1000) 
                {
                    if (tcp.Connected)
                    {
                        break;
                    }
                }
                watch.Stop();
                if (tcp.Connected)
                {
                    StatusControl.Text = watch.ElapsedMilliseconds.ToString() + " ms";
                }
                else
                {
                    StatusControl.Text = "Offline";
                }
            }
            //wait 3secs for the next request
            await Task.Delay(3000);
        }
    }

Solution

  • If you want to do an asynchronous ping request to a port along with a timeout, this code did it for me:

        private async Task<long> Ping(string host, int port, int timeOut)
        {
            long elapsed = -1;
            Stopwatch watch = new Stopwatch();
    
            using (TcpClient tcp = new TcpClient())
            {
                try
                {
                    using (CancellationTokenSource cts = new CancellationTokenSource())
                    {
                        StartConnection(host, port, tcp, watch, cts);
                        await Task.Delay(timeOut, cts.Token);
                    }
                }
                catch {}
                finally
                {
                    if (tcp.Connected)
                    {
                        tcp.GetStream().Close();
                        elapsed = watch.ElapsedMilliseconds;
                    }
                    tcp.Close();
                }
            }
    
            return elapsed;
        }
    
        private async void StartConnection(string host, int port, TcpClient tcp, Stopwatch watch, CancellationTokenSource cts)
        {
            try
            {
                watch.Start();
                await tcp.ConnectAsync(host,port);
                watch.Stop();
                cts.Cancel();
            }
            catch {}
        }
    

    It simply disposes the tcpClient as soon as the time is over and returns -1 when the server is offline or something went wrong.