Будет ли мой буфер таймера переполняться во время ожидания получения UDP?

Я пишу программное обеспечение, которое будет получать данные из пакета UDP, а затем записывать их в файл. Это пример кода, который я написал как консольное приложение для тестирования класса UdpClient.

while(!done)
{
Console.WriteLine("Receiving");
byte[] bytes = listener.Receive(ref groupEP);
Console.WriteLine("Received");
}

Я обнаружил, что если пакеты UDP не были получены, цикл while будет останавливаться на функции Receive(ref groupEP). Только когда пакет UDP получен, он продолжит печать «Получено».

Однако для реальной программы (WPF) в целях экономии ресурсов я использую вместо этого таймеры. В настоящее время он отлично работает для обновления интерфейса и файла, но мне было интересно, что произойдет, если таймер вызывается каждые 100 мс, а пакеты UDP принимаются только каждую 1 секунду (при условии, что я не знаю, когда я получу UDP поэтому я выбираю 100 мс). Не приведет ли это к 9 избыточным вызовам таймера каждую 1 секунду и не приведет ли это к переполнению? В настоящее время приложение работает нормально для этого сценария, но я хотел бы понять, почему и есть ли какие-либо возможные последствия.


person Mittens    schedule 16.11.2015    source источник


Ответы (1)


Этот вопрос граничит с «слишком широким». Вы подняли довольно много разных вопросов. Тем не менее, пытаясь быть кратким

Поведение таймера зависит от того, какой таймер вы фактически использовали. Если вы используете DispatcherTimer и вызываете Receive() из обработчика событий таймера, вы не получите избыточных событий таймера, потому что вместо этого вы будете блокировать поток пользовательского интерфейса. Что на самом деле совсем нехорошо, но, по крайней мере, не приводит к получению слишком большого количества событий таймера.

Если вы используете какой-либо другой тип таймера, тогда yesвызов новой операции Receive() до того, как вы завершение предыдущей приведет к постоянному увеличению числа еще не завершенных Receive() операций. Вы можете исправить это, переведя сокет в неблокирующий режим, но это откроет совершенно новую банку червей. Так


На самом деле вам вообще не следует использовать блокирующий метод Receive() или таймер для каких-либо целей, связанных с вводом-выводом. Вы должны использовать асинхронную версию ReceiveFrom(), например. BeginReceiveFrom(), который можно обернуть в Task.Factory.FromAsync(), чтобы можно было использовать await вместо обратных вызовов. (Вы должны использовать ReceiveFrom(), чтобы вы действительно могли получить информацию об удаленной конечной точке для полученной вами дейтаграммы).

При использовании этого метода вы зациклитесь с await (если используете FromAsync()) или снова вызовете BeginReceiveFrom() при обработке завершенной операции (если вы используете механизмы обратного вызова старого стиля). При этом вы можете одновременно активировать только одну операцию получения, но вообще не блокируя какой-либо поток, и, таким образом, нет необходимости использовать таймер или другой механизм для опроса сокета.

person Peter Duniho    schedule 16.11.2015
comment
Разве не будет то же самое, если я буду продолжать вызывать ReceiveFrom(), просто продолжая генерировать асинхронные потоки через мою функцию вызова таймера? - person Mittens; 16.11.2015
comment
Извините, если мой ответ был недостаточно ясен. Я отредактирую его, чтобы попытаться улучшить его. Вы будете вызывать BeginReceiveFrom() только один раз для каждой дейтаграммы. После первого вызова вы вообще ничего не делаете, пока он не завершится и вы не обработаете дейтаграмму. Потом снова звонишь. В этом подходе вы вообще не будете использовать таймер. - person Peter Duniho; 16.11.2015