Запуск / остановка получения данных через порт UDP через определенный интервал времени - PullRequest
1 голос
/ 30 мая 2019

У меня есть функция, которая прослушивает UDP-пакеты на конкретном порту.Всякий раз, когда я получаю данные, я хочу, чтобы функция ОСТАНОВИЛА прием данных на этом порту, подождите 5 секунд, а затем возобновила прослушивание данных.Основной поток:

  1. Прослушивание пакетов UDP.
  2. Получение пакета UDP и любая необходимая обработка этих данных.
  3. Блокировка входящих пакетов UDP и ожидание5 секунд.
  4. Повтор.

У меня работает функция, но я не могу понять, как блокировать UDP-пакеты в течение 5-секундного периода ожидания.Я использовал EnableBroadcast логическое значение на UdpClient, но он ничего не делает.Я также попытался установить SocketOptionName из Broadcast и BlockSource в true / false, и это также ничего не дает.

private async void ReceiveUdpPackets()
{
    await Task.Run(async () =>
    {
        try
        {
            while (receivePackets)
            {
                Log.Info("Listening for UDP packets...");

                listener.Client.SetSocketOption(SocketOptionLevel.Udp, SocketOptionName.BlockSource, false);
                byte[] bytes = listener.Receive(ref groupEP);
                listener.Client.SetSocketOption(SocketOptionLevel.Udp, SocketOptionName.BlockSource, true);

                Log.Info($"Received UDP broadcast from {groupEP} :");
                Log.Info($"{Encoding.ASCII.GetString(bytes, 0, bytes.Length)}");

                var bString = BitConverter.ToString(bytes).Replace("-", "");
                Log.Info("UDP ByteString: " + bString);

                DecodeByteString(bString);
                await Task.Delay(5000);
            }
        }
        catch (Exception ex)
        {
            Log.Error("There was an issue decoding the UDP packet: " + ex.ToString());
        }
    });
}

1 Ответ

0 голосов
/ 30 мая 2019

Если вы хотите, чтобы клиенты не могли отправлять что-либо в течение периода ожидания, вам понадобится какой-то способ, чтобы они знали, что сервер не находится в состоянии прослушивания.Вы можете запустить отдельную задачу на другом порту, который клиенты могут запросить, чтобы узнать, можно ли передавать и обрабатывать данные на главном порту.Есть много способов сделать это, но основная идея проста, как кажется: клиент запрашивает вторичный порт, сервер отвечает сообщением, указывающим, является ли первичный порт «подключенным».Если нет, клиент ждет, пока он не получит разрешение от сервера.Если это так, клиент может немедленно отправить свою информацию через.

Если это не звучит привлекательно, вы также можете реализовать модель очереди данных на стороне сервера.Одна задача может заполнить BlockingCollection входящими данными от клиентов и другой поток для обработки данных, извлеченных из этого источника.Обратите внимание, что это не остановит передачу, поэтому это не идеальное решение вашей проблемы, но оно имеет ряд преимуществ.Вот (некорректный) пример того, как может выглядеть код:

using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;

namespace ExampleNamespace
{

    /* 
     * data class; encapsulates byte array data received from a client. 
     * in an actual implementation this might be a nice spot to put code 
     * that interprets bytes from the client in some way
     */
    public class Transmission
    {
        public IPEndPoint Client { get; set; }

        public byte[] Data { get; set; }

        public Transmission(IPEndPoint client, byte[] data)
        {
            Client = client;
            Data = data;
        }
    }

    public class Server
    {
        private UdpClient listener;

        /*
         * you probably want to make this a bounded collection to prevent the
         * collection from getting too big
         */
        private BlockingCollection<Transmission> dataReceived = new BlockingCollection<Transmission>();

        private bool receivePackets = true;

        private bool processData = true;

        private IPEndPoint groupEP;

        public Server(IPEndPoint listenAt)
        {
            listener = new UdpClient(listenAt);
            groupEP = listenAt;
        }

        public void Run()
        {
            ProcessData();
            ReceiveData();
        }

        public async void ReceiveData()
        {
            await Task.Run(() => {
                while (receivePackets)
                {
                    byte[] data = listener.Receive(ref groupEP);
                    dataReceived.Add(new Transmission(groupEP, data));
                }
            });
        }

        public async void ProcessData()
        {
            //you could run just a few of these to increase your processing 
            //speed without changing how things work
            await Task.Run(async () => {
                while (processData)
                {
                    //blocks until data is available
                    Transmission data = dataReceived.Take();

                    //do things with the data...

                    await Task.Delay(5000);
                }
            });
        }
    }
}

Как уже говорилось, в этом примере есть некоторые проблемы - если вы действительно хотите реализовать это, я настоятельно рекомендую сделать dataReceived ограниченнымблокирует сбор, так что вам не нужно беспокоиться о проблемах с памятью.Кроме того, обычно полезно иметь возможность завершить весь процесс, передав CancellationToken на вызовы Take () и TryTake (), а также любые созданные вами потоки.Однако сам дизайн должен предусматривать простую многозадачность в случае, если обработка клиентов становится проблемой производительности.

...