TCPClient async / await C# - PullRequest
       9

TCPClient async / await C#

2 голосов
/ 30 января 2020

У меня есть несколько устройств. Программа должна постоянно пинговать эти устройства.

Столкнулся с проблемой - если соединение потеряно, то моя программа не отображает ничего, кроме первого опроса до потери соединения, и если я восстановлю соединение, то после Через 15 секунд программа начнет выводить данные.

public async Task Start(string ip)
    {
        textBox1.AppendText("Begin");
        textBox1.AppendText("\r\n");
        Stopwatch watch = new Stopwatch();

        int i = 0;

        while (true)
        {
            watch.Restart();
            using (TcpClient tcp = new TcpClient())
            {
                tcp.SendTimeout = 1000;
                try
                {
                    await tcp.ConnectAsync("192.168.127.23", 10001);
                }
                catch (SocketException)
                {
                    Debug.Assert(!tcp.Connected);
                }

                watch.Stop();
                if (tcp.Connected)
                {
                    textBox1.AppendText(i.ToString() + ") " + watch.ElapsedMilliseconds.ToString() + " ms");
                    textBox1.AppendText("\r\n");
                }
                else
                {
                    textBox1.AppendText(string.Format("{0}) Offline", i));
                }
            }

            await Task.Delay(1000);
            i++;
        }
    }

Это новый код с моими дополнениями.

public async Task Start(string ip)
    {   
        while (true)
        {
            for (int i = 0; i < devicesListActivity.Count; i++)
            {
                devicesListActivity[i].DevicesList.DevicesTotalPing++;

                string ipAdresDevice = devicesListActivity[i].DevicesList.DevicesName;
                int portDevice = devicesListActivity[i].DevicesList.DevicesPort;
                int activeDevice = devicesListActivity[i].DevicesList.DevicesActiv;
                int imageDevice = devicesListActivity[i].DevicesList.DevicesImage;
                int sendTimeDevice = devicesListActivity[i].DevicesList.DevicesTimeSend;
                int respTimeDevice = devicesListActivity[i].DevicesList.DevicesTimeResp;

                var cts = new CancellationTokenSource(sendTimeDevice);
                var ct = cts.Token;

                var t = await Task.Run<ServerStatus>(() =>
                {
                    try
                    {
                        using (TcpClient client = new TcpClient())
                        {
                            client.ConnectAsync(ipAdresDevice, portDevice).Wait(sendTimeDevice);
                            ct.ThrowIfCancellationRequested();
                            client.Close();
                            return ServerStatus.Available;
                        }
                    }
                    catch (AggregateException ex) when (ex.InnerException.GetType() == typeof(SocketException))
                    {
                        if (((SocketException)ex.InnerException).SocketErrorCode == SocketError.ConnectionRefused)
                            return ServerStatus.Refused;
                        else
                        {
                            throw new Exception("Server did not respond");
                        }

                    }
                    catch (OperationCanceledException)
                    {
                        return ServerStatus.TimeOut;
                    }
                }, ct);

                switch (t)
                {
                    case ServerStatus.Available:
                        devicesListActivity[i].DevicesList.DevicesSuccessPing++;
                        textBox1.AppendText($"{DateTime.Now.ToString()} Server available" + " " + ipAdresDevice + string.Format(" [{0}/{1}]", devicesListActivity[i].DevicesList.DevicesSuccessPing, devicesListActivity[i].DevicesList.DevicesTotalPing) + " " + System.Math.Round((double)(devicesListActivity[i].DevicesList.DevicesSuccessPing / devicesListActivity[i].DevicesList.DevicesTotalPing * 100)) +" %");
                        textBox1.AppendText("\r\n");
                        break;
                    case ServerStatus.Refused:
                        textBox1.AppendText($"{DateTime.Now.ToString()} Server refused connection." + " " + ipAdresDevice + string.Format(" [{0}/{1}]", devicesListActivity[i].DevicesList.DevicesSuccessPing, devicesListActivity[i].DevicesList.DevicesTotalPing) + " " + System.Math.Round((double)(devicesListActivity[i].DevicesList.DevicesSuccessPing / devicesListActivity[i].DevicesList.DevicesTotalPing * 100)) + " %");
                        textBox1.AppendText("\r\n");
                        break;
                    case ServerStatus.TimeOut:
                        textBox1.AppendText($"{DateTime.Now.ToString()} Server did not respond." + " " + ipAdresDevice + string.Format(" [{0}/{1}]", devicesListActivity[i].DevicesList.DevicesSuccessPing, devicesListActivity[i].DevicesList.DevicesTotalPing) + " " + System.Math.Round((double)(devicesListActivity[i].DevicesList.DevicesSuccessPing / devicesListActivity[i].DevicesList.DevicesTotalPing * 100)) + " %");
                        textBox1.AppendText("\r\n");
                        break;
                }

                // Wait 1 second before trying the test again
                await Task.Delay(1000);
            }
        }
    }

1 Ответ

2 голосов
/ 31 января 2020

Вы неправильно используете способ работы TCP Connect. Когда вы наберете client.ConnectAsync(), операционная система займет некоторое время для фактического истечения времени ожидания. Ваша настройка tcp.SendTimeout = 1000; не влияет на ConnectAsync(), управляемый операционной системой, и может длиться 20 секунд.

Итак, в этом случае вы возвращаете сервер в рабочее состояние. до истечения времени ожидания соединения и соединения.

Так что, если вы не хотите ждать 20 секунд, чтобы получить предупреждение, вам нужно будет запустить другой тайм-аут, чтобы отменить ожидающий Connect () и сообщить, что вы не в сети. Например, если вы не получите ответ в течение 1 секунды, отчет будет отключен.

Кроме того, если соединение не установлено из-за его активного отказа, вам также потребуется обработать этот тестовый пример. Отказ обычно означает, что ваш сервер включен, но порт не прослушивает. Однако это также может быть брандмауэр, активно отказывающий в соединении, в этом случае вы не знаете, работает ли сервер.

Рассмотрим следующий пример кода, который обеспечивает базовый c TCP-мониторинг порта:

private async void btnTest_Click(object sender, EventArgs e)
{
    int timeOut = 2000;

    while (true)
    {
        using (TcpClient client = new TcpClient())
        {
            var ca = client.ConnectAsync("127.0.0.1", 9999);
            await Task.WhenAny(ca, Task.Delay(timeOut));
            client.Close();
            if (ca.IsFaulted || !ca.IsCompleted)
                listBox1.Items.Add($"{DateTime.Now.ToString()} Server offline.");
            else
                listBox1.Items.Add($"{DateTime.Now.ToString()} Server available.");
        }
        // Wait 1 second before trying the test again
        await Task.Delay(1000);
    }
}
...