Re: Как корректно остановить асинхронное чтение из UdpClient
От: merk Россия  
Дата: 23.07.08 11:23
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Добрый день!


А>Пишу класс DataReceiver, получающий UDP пакеты и передающий их в очередь для дальнейшей обработки. Получение реализовано с использованием асинхронных методов BeginReceive, EndReceive класса UdpClient.


чиста теоретические рассуждения, поскольку деталей приема udp пакетов не знаю.
буду писать некие общие замечания.


А>
А>    public class DataReceiver : IDisposable
А>    {
А>        private UdpClient _client;
А>        private bool _disposed;

А>        public void Start()
А>        {
А>            _client.BeginReceive(ReceiveCallback, null);
А>        }

А>        public void Stop()
А>        {
А>            _client.Close();
А>        }
если в старте вы начали прием, то в стопе долна быть явная функция снимающая колбек. если close это обеспечивает, то и хорошо. если нет - нужно писать видимо EndReceive явно прямо тут. только возникнут вопросы синхронизации. если в данный момент будет исполняться колбек могут быть проблемы. надо посмотреть доки как правильно снимать колбеки. поскольку случай существенно получается мультиредовый(колбек вызывается тредом обслуживающим их, а не текущим).


А>        private void ReceiveCallback(IAsyncResult ar)
А>        {
А>            IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);

нельзя ли как то избавиться от new в колбеке? колбек должен быь минимальной функцией обеспечивающей вашу "идею". его задача взять данные и куда-то быстро перепихнуть вашим тредам. и уж там вы будете с этими данными разбираться.

А>            try
А>            {
А>                byte[] data = _client.EndReceive(ar, ref remoteEP);
тут вопрос. это колбек дезактвируется и пока не скажут стартресив - вызываться не будет?
это плохо. колбеку нежелательно управлять самим собой. обычно колбэк должен взводить булеву переменную на вхлоде - нахожусь_внутри_колбека, и проверять ее перед этим. при выходе - ставить переменную в false, таким образом контролируется повторный вход в колбек. повторный вход в колбек служит признаком того что вы захлебываетесь в обработке. нужно принимать какие-то меры.


А>                // Передача на обработку подписчику ...

А>                _client.BeginReceive(ReceiveCallback, null);
А>            }
А>            catch (ObjectDisposedException)
А>            { /* Stopped? */ }
А>            catch (SocketException)
А>            { /* Stopped? */ }

 в колбеке, поскольку он вызывается неким не вашим тредом, я думаю разумно перехватить все эксепшены. а лучше сократить его функциональность до достаточно элементарных операции, чтобы самих эксепшенов было поменьше.
А>        }

А>        /* IDisposable Members implementation */
А>    }
А>


А>Корректна ли данная реализация? Как правильно остановить получение данных?


правильно остановить снятием колбека не из него самого.

А>В приведенном коде меня смущает необходимость перехватывать ObjectDisposedException и SocketException внутри ReceiveCallback. Эти исключения возникают, если ReceiveCallback срабатывает в результате или после вызова _client.Close. Поэтому в принципе, видится нормальным их перехват: DataReceiver полагает, что остановлен и не делает новых запросов на получение пакетов. Однако SocketException может возникнуть и "штатно", DataReceiver в этом случае поведет себя неправильно: прекратит дальнейшее получение пакетов.


вот потому то перед client.close должен явно снять колбек, но аккуратно(см выше).

А>Фактически, здесь проблема использования ресурса из разных потоков. UdpClient используется из основного потока, вызывающего Start, Stop, и потоками из пула, в контексте которых срабатывает ReceiveCallback. Возможно, стоит ввести флаг "остановлен" и синхронизировать доступ к нему и UdpClient? А как быть с блокировкой, которая появится в реализации Dispose?

никак не быть с блокировкой. если endRecieve , блокирующая операция до момента физического снятия колбека — то это естественная блокировка.
еще хуже блокировки в колбеке за счет вызова каких то ваших "передач данных подписчикам". именно в колбеке важно не иметь блокировок, способных затянуть во времени исполнение колбека.

А>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.