UdpClient не будет подключаться к IpAdress.Any

#c# #network-programming

#c# #сетевое программирование

Вопрос:

Я пытаюсь прослушивать UDP-пакеты из неизвестного источника. Но не может привязаться к «неуказанному адресу» (0.0.0.0 или ::)

Я уже пробовал прослушивать ::1. Но из того, что я тестировал, это работает только для локальных подключений, которые не передают сетевой интерфейс.

         public async void AwaitDiscoveryReply()
        {
            try
            {
                using (var client = new UdpClient(AddressFamily.InterNetworkV6))
                {
                    client.Connect(IPAddress.IPv6Any,4568);

                        var result = await client.ReceiveAsync();
                        Debug.WriteLine("Received DR");
                        var stateProtocol = StateProtocol.FromBytes(result.Buffer);
                        var robeatsDevice = new RobeatsDevice
                        {
                            Id = stateProtocol.DeviceId,
                            Name = stateProtocol.DeviceName,
                            EndPoint = client.Client.RemoteEndPoint,
                            StateProtocol = stateProtocol

                        };
                        OnDiscoveryReply(new DeviceDiscoveryEventArgs {RobeatsDevice = robeatsDevice});

                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex);
            }
        }
 

Это продолжает вызывать исключение: The requested address is not valid in its context [::]:4568

Комментарии:

1. Вы используете IPV4 или IPV6?

2. IPV6, но я не думаю, что это действительно имеет значение в данном случае

3. Тогда порт уже используется. Попробуйте использовать из cmd.exe > Netstat -a, чтобы увидеть, какие порты используются.

4. jdweng — Если адрес уже был привязан, в сообщении об ошибке это будет четко указано.

Ответ №1:

Сокеты UDP не имеют соединения. Методы «Connect» в реализациях сокетов UDP по соглашению (не спрашивайте меня, почему) устанавливают конечные точки по умолчанию / фильтруют трафик. Если вы хотите получать трафик с любого адреса, вам вообще не нужно «подключаться». Используйте конструктор с подписью UdpClient(Int32, AddressFamily) и удалите вызов Connect():

 public async void AwaitDiscoveryReply()
      {
          try
        {
            using (var client = new UdpClient(4568,AddressFamily.InterNetworkV6))
            {

                    var result = await client.ReceiveAsync();
                    Debug.WriteLine("Received DR");
                    var stateProtocol = StateProtocol.FromBytes(result.Buffer);
                    var robeatsDevice = new RobeatsDevice
                    {
                        Id = stateProtocol.DeviceId,
                        Name = stateProtocol.DeviceName,
                        EndPoint = client.Client.RemoteEndPoint,
                        StateProtocol = stateProtocol

                    };
                    OnDiscoveryReply(new DeviceDiscoveryEventArgs {RobeatsDevice = robeatsDevice});

            }
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex);
        }
    }
 

Комментарии:

1. (кстати, я бы предложил использовать, Receive() а не ReceiveAsync() для ясности …)

2. Почему это? Из-за ожидания?

3. также это дает мне System.Net.Sockets.SocketException (0x80004005): A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied

4. Я предполагаю, что последнее было выброшено из-под вашего OnDiscoveryReply() , которое вы не показываете. Как указано в сообщениях об ошибках, вы должны указать адрес при отправке данных — опять же, потому что UDP не имеет соединения. Мы видим только ваше получение здесь.

5. Receive() для сокетов в режиме блокировки (по умолчанию, которые вы используете). ReceiveAsync() для общего случая. Он будет работать как есть, но всегда делает то же самое, что и Receive() , возвращая false .