2010-07-07 15 views
7

Devo essere in grado di inviare un messaggio UDP e anche riceverne uno per scoprire dispositivi SSDP sulla rete da iPhone.SSDP su iPhone

So che ho bisogno di inviare il pacchetto all'indirizzo multicast e la mia richiesta HTTP ha bisogno di guardare qualcosa di simile:

M-SEARCH * HTTP/1.1 
Host: 239.255.255.250:1900 
Man: ssdp:discover 
Mx: 3 
ST: "urn:schemas-upnp-org:device:InternetGatewayDevice:1" 

Dalla lettura dei documenti risulta che posso fare tutto questo con CFNetwork e nonostante la lettura (e la rilettura dei documenti) sto faticando per iniziare. Qualcuno può consigliare e tutorial o frammenti di codice per farmi sopra la gobba di apprendimento iniziale?

Ho la guida di programmazione CFNetwork:

http://developer.apple.com/mac/library/documentation/Networking/Conceptual/CFNetwork/CFNetwork.pdf

e di Beej Guida alla programmazione Uso delle prese della rete Internet:

http://beej.us/guide/bgnet/

Grazie

Dave

P.S.

In questa istanza non riesco a utilizzare nessuna delle librerie e dei framework di terze parti.

risposta

2

OK, finalmente fatto. Ho trovato una classe di dominio pubblico (grazie a Chris) chiamata AsyncUdpSocket che consente di creare un socket UDP che è possibile attivare la trasmissione e unire l'indirizzo multicast.

C'è un bel metodo sendData, completo con l'aggiunta a un ciclo di esecuzione per impedire il blocco.

Spero che questo aiuti.

Dave

4

Ho il seguente codice per la ricerca SSDP nella mia app:

-(void)discoverDevices { 
ssdpSock = [[AsyncUdpSocket alloc] initWithDelegate:self]; 
[ssdpSock enableBroadcast:TRUE error:nil]; 
NSString *str = @"M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMan: \"ssdp:discover\"\r\nST: mydev\r\n\r\n";  
[ssdpSock bindToPort:0 error:nil]; 
[ssdpSock joinMulticastGroup:@"239.255.255.250" error:nil]; 
[ssdpSock sendData:[str dataUsingEncoding:NSUTF8StringEncoding] 
     toHost: @"239.255.255.250" port: 1900 withTimeout:-1 tag:1]; 
[ssdpSock receiveWithTimeout: -1 tag:1]; 
[NSTimer scheduledTimerWithTimeInterval: 5 target: self 
      selector:@selector(completeSearch:) userInfo: self repeats: NO]; } 


-(void) completeSearch: (NSTimer *)t { 
NSLog(@"%s",__FUNCTION__); 
[ssdpSock close]; 
ssdpSock = nil;} 

- (BOOL)onUdpSocket:(AsyncUdpSocket *)sock didReceiveData:(NSData *)data withTag:(long)tag fromHost:(NSString *)host port:(UInt16)port{ 
NSLog(@"%s %d %@ %d",__FUNCTION__,tag,host,port); 
NSString *aStr = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; 
NSLog(@"%@",aStr);} 

Si utilizza il AsyncUdpSocket da CocoaAsyncSocket.

+4

Ciao Savvybud, sembra ok, ma dalla parte superiore della mia testa (è stato qualche tempo fa l'ho fatto) Penso che il tuo problema risiede nel bindToPort. Sono abbastanza sicuro che questa sia la porta che invierà i messaggi e non dovrebbe essere 1900 poiché è riservata ai multicast. Se si imposta questo a zero, il sistema ne assegnerà uno e dovrebbe funzionare. sendData sembra a posto. –

+0

Magic Bullet Dave, tu sei l'uomo! – savvybud

4

Ho utilizzato AsyncUdpSocket correttamente per eseguire SSDP Discovery e trovare i controller. Qui sono i miei frammenti di codice:

inizializzazione e la configurazione della presa:

// AsyncUdpSocket *ssdpSock = [[AsyncUdpSocket alloc] initWithDelegate:self]; 
    AsyncUdpSocket *ssdpSock = [[AsyncUdpSocket alloc] initIPv4]; 
    [ssdpSock setDelegate:self]; 

Nota la prima linea commentata. Ho trovato su AsyncUdpSocket forums alcuni problemi con i duplicati. Non penso di essere di fronte a loro, ma l'ho fatto comunque.

ho aggiunto il controllo degli errori, ed è stato utile perché durante la mia debug non ero chiudendo le prese e ho cominciato a ricevere gli errori di impostazione presa:

NSError *socketError = nil; 

    if (![ssdpSock bindToPort:1900 error:&socketError]) { 
     NSLog(@"Failed binding socket: %@", [socketError localizedDescription]); 
     return statusController; 
    } 

    if(![ssdpSock joinMulticastGroup:@"239.255.255.250" error:&socketError]){ 
     NSLog(@"Failed joining multicast group: %@", [socketError localizedDescription]); 
     return statusController; 
    } 

    if (![ssdpSock enableBroadcast:TRUE error:&socketError]){ 
     NSLog(@"Failed enabling broadcast: %@", [socketError localizedDescription]); 
     return statusController; 
    } 

    [ssdpSock sendData:[self.discoverControllerString dataUsingEncoding:NSUTF8StringEncoding] 
       toHost:@"239.255.255.250" 
        port:1900 
      withTimeout:2 
        tag:1]; 

notare i cambiamenti che ho fatto per il time out. E poi finalmente ha fatto il setup di ricezione, e ha chiuso lo zoccolo. Notare la chiusura della presa. Dato che sono nella mia classe quando sto eseguendo questo, il codice sopra non ha funzionato per me.

[ssdpSock receiveWithTimeout: 2 tag:1]; 
    [NSTimer scheduledTimerWithTimeInterval: 5 target: self 
            selector:@selector(completeSearch:) userInfo: self repeats: NO]; 





    [ssdpSock closeAfterSendingAndReceiving]; 

Il cambiamento più importante probabilmente è stato restituire "NO" se non ho trovato il mio controller. La prima ricezione fu incidentalmente il messaggio di scoperta stesso che ritornava. E quando leggo attentamente il file AsyncUdpSocket.h - restituisco "NO" quando non è un pacchetto che stai cercando aiutato.

Si noti inoltre che sto usando ARC nel mio codice ma ho compilato AsyncUdpSocket senza supporto ARC.

-(void) completeSearch: (NSTimer *)t 
{ 

    NSLog(@"%s",__FUNCTION__); 

    //[ssdpSock close]; 
    //ssdpSock = nil; 

} 


- (BOOL)onUdpSocket:(AsyncUdpSocket *)sock 
    didReceiveData:(NSData *)data 
      withTag:(long)tag 
      fromHost:(NSString *)host 
       port:(UInt16)port 
{ 
    NSLog(@"%s %ld %@ %d",__FUNCTION__,tag,host,port); 
    NSString *aStr = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; 

    NSLog(@"%@",aStr); 



    NSString *compareString = [aStr stringByPaddingToLength:[self.responseString length] withString:@"." startingAtIndex:0]; 
    //NSLog(@"%@", compareString); 
    //NSLog(@"%@", self.responseString); 

    if ([compareString isEqualToString:self.responseString]) 
    { 
     NSLog(@"String Compare, Controller Found!"); 
     [self.controllerList addObject:aStr]; 
     //NSData *controllerIP = [aStr dataUsingEncoding:NSUTF8StringEncoding]; 
     [[NSNotificationCenter defaultCenter] postNotificationName:@"DiscoveredController" object:nil]; 


     return YES; 
    } 

    return NO; 

} 
+0

Sto usando l'approccio sopra descritto, per scoprire una action cam sony. Sulla riga [ssdpSock bindToPort: 1900 errore: & socketError] appare sul debugger CFSocketSetAddress ascolto fallito: 102, tuttavia tutto è a posto, la scoperta avviene con successo. Che diamine vuol dire questo fallimento: 102 Non lo so. Qualche idea? PS: Se scavo un po 'più in profondità, la linea in cui si verifica è Errore CFSocketError = CFSocketSetAddress (theSocket4, (__bridge CFDataRef) address4); Il valore di errore è kCFSocketSuccess –