Как мне узнать, был ли UdpClient закрыт / удален? - PullRequest
4 голосов
/ 16 февраля 2012

Я получаю данные от UdpClient через обычный асинхронный обратный вызов:

private void OnUdpData(IAsyncResult result)
{
    byte[] data = _udpReceive.EndReceive(result, ref _receiveEndPoint);

    //Snip doing stuff with data

    _udpReceive.BeginReceive(OnUdpData, null);
}

Когда я Close() UdpClient в главном потоке, обратный вызов срабатывает, как я и ожидал, но в этот момент _udpReceive уже удален, и я получаю ObjectDisposedException, когда пытаюсь позвонить EndReceive(). Я ожидал получить пустой буфер.

Как правильно справиться с этим? Есть ли какой-нибудь член UdpClient, который я могу проверить, прежде чем пытаться его использовать, или это единственный способ обернуть все это в try{} и поймать ObjectDisposedException? Это кажется довольно неприятным для нормального закрытия.

Ответы [ 2 ]

5 голосов
/ 16 февраля 2012

Вы можете сделать это, чтобы проверить, утилизирован ли он. При удалении UdpClient клиенту присваивается значение null.

private void OnUdpData(IAsyncResult result)
{
    if (_udpReceive.Client == null)
        return;
    byte[] data = _udpReceive.EndReceive(result, ref _receiveEndPoint);

    //Snip doing stuff with data

    if (_udpReceive.Client == null)
        return;
    _udpReceive.BeginReceive(OnUdpData, null);
}

Хотя, поскольку вы закрываете его в отдельном потоке, у вас может возникнуть состояние гонки. Лучше всего просто перехватить ObjectDisposedException и SocketException.

private void OnUdpData(IAsyncResult result)
{
    try
    {
        byte[] data = _udpReceive.EndReceive(result, ref _receiveEndPoint);

        //Snip doing stuff with data

        _udpReceive.BeginReceive(OnUdpData, null);
    }
    catch (Exception e)
    {
        //You may also get a SocketException if you close it in a separate thread.
        if (e is ObjectDisposedException || e is SocketException)
        {
            //Log it as a trace here
            return;
        }
        //Wasn't an exception we were looking for so rethrow it.
        throw;
    }
}
4 голосов
/ 16 февраля 2012

Это полностью задумано.Вы сделали что-то исключительное, вы закрыли сокет, хотя ожидали, что данные будут получены.Таким образом, вы получите исключение..NET Framework всегда гарантирует, что асинхронные вызовы завершены и что причина прерывания сообщается в обратном вызове при вызове EndXxx ().Хорошая идея, которая позволяет очистить любое состояние, связанное с обратным вызовом.

Вы можете сделать его неисключительным, дождавшись завершения передачи, прекратить вызывать BeginReceive () и затем closeрозетка.Но это не всегда практично, а иногда вы действительно хотите закончить рано.Не проблема, просто перехватите ObjectDisposedException и выйдите.Конечно, do учитывает, что происходит с приложением на другом конце провода.Все, что он отправит позже, попадет в корзину, и у него не будет возможности это выяснить.

...