GCDAsyncUdpSocket sur les datagrammes multicast manquants iOS

J'ai un périphérique sur le réseau qui diffuse un très petit file via UDP. L'application iOS que je développe est responsable de la lecture de ces packages et j'ai choisi d'utiliser GCDAsyncUdpSocket pour le faire. Le file est envoyé toutes les demi-secondes, mais je ne le reçois presque pas aussi souvent (seulement environ 3 à 10 secondes).

Pensant que cela pourrait être un problème avec l'appareil, j'ai commencé à surveiller le trafic avec Wireshark. Cela semblait refléter ce que je voyais dans mon application jusqu'à ce que j'active le "Mode de surveillance" dans Wireshark, à quel point chaque package UDP était capturé. En outre, le simulateur iOS a commencé à recevoir tous les packages manquants, car il partage la carte réseau avec le Mac que je développe.

Y a-t-il un moyen d'activer "Monitor Mode" sur un appareil iOS ou quelque chose qui me manque qui permettrait aux packages manquants d'entrer? Je vois aussi qu'il y a une méthode readStream dans GCDAsyncUdpSocket. Peut-être que j'ai besoin de l'utiliser au lieu de commencer à recevoir? Bien que je ne sache pas comment mettre en place des stream en Objective-C si c'est le cas.

Voici mon code de test tel qu'il est maintenant:

- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. NSLog(@"View Loaded"); [self setupSocket]; } - (void)setupSocket { udpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()]; NSError *error = nil; if (![udpSocket bindToPort:5555 error:&error]) { NSLog(@"Error binding to port: %@", error); return; } if(![udpSocket joinMulticastGroup:@"226.1.1.1" error:&error]){ NSLog(@"Error connecting to multicast group: %@", error); return; } if (![udpSocket beginReceiving:&error]) { NSLog(@"Error receiving: %@", error); return; } NSLog(@"Socket Ready"); } - (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data fromAddress:(NSData *)address withFilterContext:(id)filterContext { NSSsortingng *msg = [[NSSsortingng alloc] initWithData:data encoding:NSUTF8SsortingngEncoding]; if (msg) { NSLog(@"RCV: %@", msg); } else { NSSsortingng *host = nil; uint16_t port = 0; [GCDAsyncUdpSocket getHost:&host port:&port fromAddress:address]; NSLog(@"Unknown message from : %@:%hu", host, port); } } 

Solution pour tous ceux qui viennent chercher ici à l'avenir:

Sur la base de la réponse d'ilmiacs, j'ai pu réduire de manière significative le nombre de packages manquants en envoyant une requête ping à l'appareil iOS cible. En utilisant un Mac, j'ai couru cela dans le terminal –

 sudo ping -i 0.2 -s 4 <Target IP> 

Maintenant que je l'ai exécuté avec un Mac qui envoie un ping sur l'appareil iOS, je vais regarder dans les exemples de ping iOS d'Apple et voir si je peux avoir le périphérique ping lui-même pour stimuler son propre adaptateur sans fil (127.0.0.1).

    Grâce à mon travail sur les applications de mise en réseau pour les appareils iOS, j'ai révélé que leurs adaptateurs réseau ont deux modes différents, appelons-les actifs et passifs. Je n'ai pas réussi à find de documentation à ce sujet. Voici mes conclusions:

    1. Tant que le mode actif est actif, l'adaptateur est très réactif. J'ai des time de réponse de 3-5ms.

    2. Après un certain time d'inactivité, l'adaptateur réseau de l'iOS passe du mode actif au mode passif. L'heure à laquelle cela doit se produire dépend du model de périphérique réel. 3ème génération iPad c'est environ 200ms. Pour l'iPhone 4 c'est plus comme 50ms.

    3. Une requête ping ou un package TCP va déplacer l'adaptateur du mode passif au mode actif. Cela peut prendre de 50ms à 800ms, avec une moyenne d'environ 200ms.

    Ce comportement est complètement reproductible en émettant des commands ping. Par exemple

     ping -i 0.2 <ios-device-ip> 

    Définit l'intervalle ping à 200 ms et maintient ma carte réseau iPad à l'état actif.

    Ce comportement est complètement cohérent avec vos observations, si l'adaptateur (le plus souvent) ignore les packages UDP en mode passif. L'activité wireshark le garde probablement en mode actif, alors il obtiendrait les UDP.

    Découvrez si le truc de ping aide.

    On pourrait probablement garder l'adaptateur réseau de l'iDevice dans l'état actif en ouvrant et en connectant deux sockets sur l'appareil lui-même et en lui envoyant régulièrement des packages. Cela introduirait des frais généraux minimes.

    Quant à savoir pourquoi Apple a décidé de mettre en œuvre une telle fonctionnalité, je ne peux que spéculer sur. Mais le fait de garder l'adaptateur actif coûte probablement suffisamment d'énergie pour légitimer un tel choix de design.

    J'espère que cela t'aides.

    J'ai eu le même problème.

    Le démarrage de l'indicateur d'activité réseau a résolu ce problème pour moi:

     UIApplication* app = [UIApplication sharedApplication]; app.networkActivityIndicatorVisible = YES; 

    Si vous voulez voir le package sur l'appareil iOS, vous pouvez connecter votre appareil iOS à un Mac et monter l'adaptateur wifi en utilisant la command shell rvictl . Vous pouvez ensuite utiliser wireshark, tcpdump, etc. pour surveiller le trafic sur votre interface 802.11 sur votre appareil iOS.

    Si vous ne recevez pas de données pendant 3 à 7 secondes – Votre appareil passe probablement en mode d'économie d'énergie (IEEE PSM), qui est une fonctionnalité 802.11 qui met essentiellement la carte réseau sans fil en veille.
    Le mode PSM peut entraîner des performances médiocres sur les périphériques , en particulier dans le cas où vous avez des rafales de données périodiques toutes les 1/2 secondes. Votre ping périodique réveille la carte réseau.