Очень высокая потеря пакетов 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