Very high UDP packet loss on iOS (GCDAsyncUdpSockets)
I am working on an iPhone application to control physical hardware.
The procedure is as follows:
- application
- sends a specific 8-byte "wake up" datagram on the broadcast channel, on port 8089; the message is resent.
- external equipment that listens to port 8089, receives the message and sends a 94-byte datagram containing, among other things, the IP address and MAC address of the hardware; this also applies to the broadcast channel. application
- stops sending the wake-up message, stores the IP address, and starts communicating with the equipment over the TCP socket
The procedure usually works. However, I often get unexplained UDP packet receive loss; that is, I am sending an 8 byte wake up signal, but I am not receiving a 94 byte response. When the application works, it works great: I hardly ever lose one packet, and if the application misses the first 94-byte message, it gets the second or third. When it is down, it skips all packets, all the time. The “non-working” stage can last minutes or hours; I did not find any obvious trigger - as if at some stage, for no reason, the trick stops working.
I did some very extensive debugging before asking the question. I have monitored sockets through rvictl and tcpdump and verified that my logs reflect what is happening at the socket level. To take external hardware out of the equation, I created a mirrored application that behaves like hardware. I tried changing ports, I tried to close and nil sockets all the time, until resetting them to pause and restart receiving. None of this worked.
I have developed my communication library with GCDAsyncUdpSocket. To be on the safe side, I experimented with the non-GCD version as well; The result is the same. I've built my own minimal wrapper around C sockets; I have the same behavior.
Here is my implementation code:
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];
}
Do you have any suggestions? Is there a way to make sure that socket reception never stops?
Thanks in advance,
Davide
source to share
No one has answered this question yet
See similar questions:
or similar: