Очень высокая потеря пакетов UDP на iOs (GCDAsyncUdpSockets)

Я работаю над приложением для iPhone для управления физическим оборудованием.
Процедура выглядит следующим образом:

  • приложение отправляет конкретную 8-байтовую дейтаграмму "пробуждения" по широковещательному каналу на порт 8089; сообщение повторно отправлено.
  • внешнее оборудование, которое прослушивает порт 8089, принимает сообщение и отправляет 94-байтовую дейтаграмму, содержащую, помимо прочего, IP и MAC-адрес оборудования; это также на канале вещания.
  • приложение прекращает отправку сообщения "проснуться", сохраняет IP-адрес и начинает взаимодействовать с оборудованием через TCP-сокет

Процедура в целом работает. Однако я часто получаю необъяснимую потерю пакетов UDP при получении; то есть я посылаю 8-байтовый сигнал "пробуждения", но я не получаю ответ 94 байта. Когда приложение работает, оно работает отлично: я почти не теряю ни одного пакета, а если приложение пропускает первое 94-байтовое сообщение, оно получает второе или третье. Когда это не работает, оно постоянно пропускает все пакеты. Этап "не работает" может длиться минуты или часы; Я не нашел очевидного триггера - как будто на каком-то этапе без причины прием перестает работать.

Прежде чем спросить здесь, я сделал очень обширную отладку. Я контролировал сокеты через rvictl и tcpdump и подтвердил, что мои журналы отражают то, что происходит на уровне сокетов. Чтобы вывести внешнее оборудование из уравнения, я создал зеркальное приложение, которое ведет себя так, как должно работать оборудование. Я попытался изменить порты, я пытался все время закрывать и обнулять сокеты, сбрасывать их, приостанавливать и возобновлять прием. Ничего из этого не сработало.

Я разработал свою коммуникационную библиотеку с помощью GCDAsyncUdpSocket. Чтобы быть в безопасности, я экспериментировал также с не GCD-версией; результат тот же. Я построил свою собственную минимальную оболочку вокруг C-сокетов; У меня такое же поведение.

Вот мой код реализации:

GCDAsyncUdpSocket *udpSocket;

- (void)startUdpBroadcast {

    if (udpSocket == nil)
    {
        // Setup our socket.
        udpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
        [udpSocket setIPv6Enabled:NO];
    }

    NSLog(@"Listening for a message on %@",[self getBroadcastAddress]);

    NSError *bindError = nil;
    NSError *enableError = nil;
    NSError *receivingError = nil;

    [udpSocket bindToPort:8089 error:&bindError];
    if (bindError) {
        NSLog(@"Error, can't bind: %@",[bindError localizedDescription]);
        return;
    }
    [udpSocket enableBroadcast:YES error:&enableError];
    if (enableError) {
        NSLog(@"Error, can't enable broadcast: %@",[enableError localizedDescription]);
        return;
    }

    if (![udpSocket beginReceiving:&receivingError])
    {
        NSLog(@"Error, can't receive: %@",[receivingError localizedDescription]);
        return;
    }

    [self logInfo:@"Start listening to UDP boradcast channel"];

    [self sendUdpSignal];

    repeatedBroadcastTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(sendUdpSignal) userInfo:nil repeats:YES];

}

-(void)sendUdpSignal {
    NSData* signal = [self udpBroadcastSignal] ;
    NSLog(@"Send broadcast signal %@ on %@",signal,  [self currentNetworkSsid]);
    [udpSocket sendData:signal toHost:[self getBroadcastAddress] port:8089 withTimeout:10 tag:0];
}

Есть ли у вас предложения?
Есть ли способ убедиться, что прием через сокет никогда не прекращается?

Заранее спасибо,
Davide

0 ответов

Другие вопросы по тегам