Я работаю над приложением для 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];
}
Есть ли у вас какие-либо предложения?
Есть ли способ убедиться, что прием сокетов никогда не прекращается?
Заранее спасибо,
Давиде