Где находится UdpClient.CancelReceive? - PullRequest
4 голосов
/ 08 мая 2009

Я реализую простой протокол обнаружения локальной сети, поэтому я вызываю UdpClient.Send, а затем UdpClient.BeginReceive. Если ожидается более одного ответа, я вызываю UdpClient.BeginReceive в конце обратного вызова. Примерно так:

UdpClient client = new UdpClient(AddressFamily.InterNetwork);
client.EnableBroadcast = true;
client.Send(request, request.Length, broadcastEndPoint);
client.BeginReceive(Callback, client);

... а затем в Callback:

void Callback(IAsyncResult ar)
{
    UdpClient client = (UdpClient)ar.AsyncState;
    IPEndPoint remoteEndPoint = null;
    byte[] response = client.EndReceive(ar, ref remoteEndPoint);

    // Do something with response

    client.BeginReceive(Callback, client);
}

Моя проблема заключается в том, что мой основной цикл вызывает client.Close, пока еще есть ожидающие получения. Прием завершается, и мой следующий вызов BeginReceive выдает исключение: System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host

Почему в UdpClient нет метода CancelReceive? Что я могу сделать вместо этого?

Ответы [ 2 ]

6 голосов
/ 08 сентября 2009

Вместо этого или для преодоления этого исключения создайте bool и установите его перед выполнением команды закрытия, используйте этот bool для проверки обратного вызова

как это

bool isClosing=false;
void Callback(IAsyncResult ar)
{
    if(isClosing) return;
}

установить bool isClosing перед выполнением команды закрытия

3 голосов
/ 15 октября 2013

Использование флага isClosing для уведомления функции обратного вызова о том, что UdpClient больше не доступен, не является правильным решением. При выполнении обратного вызова в другом потоке всегда есть вероятность, что соединение закрывается после проверки флага isClosing и перед вызовом BeginReceive (или EndReceive).

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

Чтобы отменить ожидающий вызов метода BeginConnect (), закройте Разъем. Когда метод Close () вызывается во время асинхронного операция в процессе, обратный вызов предоставлен BeginConnect () метод называется. Последующий вызов EndConnect (IAsyncResult) Метод сгенерирует исключение ObjectDisposedException, чтобы указать, что операция была отменена.

Итак, пример кода будет выглядеть так:

void Callback(IAsyncResult ar)
{
    try
    {
        UdpClient client = (UdpClient)ar.AsyncState;
        IPEndPoint remoteEndPoint = null;
        byte[] response = client.EndReceive(ar, ref remoteEndPoint);

        // Do something with response

        client.BeginReceive(Callback, client);
    }
    catch (SocketException e)
    {
        // Oups, connection was closed
    }
    catch (ObjectDisposedException e)
    {
        // Oups, client was disposed
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...