3

I am working on an iPhone app for controlling physical hardware.
The routine is as follows:

  • app sends a specific 8-bytes "wake up" datagram on the broadcast channel, on port 8089; the message is repeatedly sent.
  • external hardware, which is listening to port 8089, receives the message and sends a 94 bytes datagram containing, among other stuff, the IP and MAC address of the hardware; this is also on the broadcast channel.
  • app stops sending the "wake up" message, stores IP, and begins communicating with the hardware via a TCP socket

The routine generally works. However, I often get an inexplicable loss of UDP packages on reception; that is, I send the 8-bytes "wake up" signal, but I don't get the 94 bytes response. When the app works, it works perfectly: I hardly lose a single package, and if the app misses the first 94-bytes message, it gets the second or third one. When it doesn't work, it misses all packages, constantly. The "not-working" stage might last for minutes, or hours; I've found no apparent trigger - it's as if at some stage, with no reason, reception stops working.

Before asking here, I've done very extensive debugging. I've monitored the sockets via rvictl and tcpdump, and confirmed that my logs reflect what happens at the socket level. To take the external hardware out of the equation, I've built a mirror app that behaves as the hardware should. I've tried changing ports, I tried to close and nil sockets all times, to reset them , to pause and restart reception. None of this worked.

I've developed my communication library with GCDAsyncUdpSocket. To be on the safe side, I've experimented also with the non GCD version; the result is the same. I built my own minimal wrapper around C sockets; I got the same behaviour.

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 suggestion?
Is there a way to make sure socket reception is never stopped?

Thanks in advance,
Davide

Anton Savin
  • 40,838
  • 8
  • 54
  • 90
Davide
  • 31
  • 1
  • Answered here: http://stackoverflow.com/questions/13113435/gcdasyncudpsocket-on-ios-missing-multicasted-datagrams – Sebas Aug 18 '15 at 14:37

0 Answers0