2010-07-07 15 views
7

Necesito poder enviar un mensaje UDP y también recibir uno para descubrir dispositivos SSDP en la red desde el iPhone.SSDP en el iPhone

Sé que tengo que enviar el paquete a la dirección de multidifusión y mi solicitud HTTP tiene que ser algo como esto:

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

De la lectura de los documentos se desprende que puedo hacer todo esto con CFNetwork y a pesar de leer (y volver a leer los documentos) estoy luchando por comenzar. ¿Alguien puede recomendar y tutoriales o fragmentos de código para superar la joroba de aprendizaje inicial?

Tengo la guía de programación CFNetwork:

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

y la Guía del Beej programación de red con sockets de Internet:

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

Gracias

de Dave

P.S.

No puedo usar ninguna de las bibliotecas y marcos de terceros en esta instancia.

Respuesta

2

OK, finalmente lo ha hecho. Encontré una clase en el dominio público (gracias Chris) llamada AsyncUdpSocket que le permite crear un socket UDP que luego puede activar la difusión y unirse a la dirección de multidifusión.

Hay un buen método sendData, completo con agregar a un ciclo de ejecución para evitar el bloqueo.

Espero que ayude.

de Dave

4

he el siguiente código para el SSDP búsqueda en mi aplicación:

-(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);} 

Se utiliza el AsyncUdpSocket de CocoaAsyncSocket.

+4

Hola Savvybud, se ve bien, pero desde lo más alto de mi cabeza (hace un tiempo esto lo hice), creo que tu problema está en bindToPort. Estoy bastante seguro de que este es el puerto donde se enviarán los mensajes de devolución y no debería ser 1900, ya que está reservado para multidifusiones. Si establece esto en cero, el sistema asignará uno y debería funcionar. sendData se ve bien. –

+0

Magic Bullet ¡Dave, eres el hombre! – savvybud

4

He utilizado AsyncUdpSocket con éxito para ejecutar SSDP Discovery y encontrar controladores. Aquí están mis fragmentos de código:

inicializar y configurar el zócalo:

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

nota la primera línea comentada. Encontré en el AsyncUdpSocket forums algunos problemas con los duplicados. No creo que los enfrentara, pero lo hice de todos modos.

he añadido la comprobación de errores, y era útil porque durante mi depuración no estaba cerrando los zócalos y empecé a recibir errores de instalación del zócalo:

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]; 

Aviso los cambios que he hecho para el tiempo de espera. Y finalmente hizo la configuración de recepción y cerró el socket. Tenga en cuenta que el socket está cerca. Como estoy en mi propia clase cuando estoy ejecutando esto, el código anterior no funcionó para mí.

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





    [ssdpSock closeAfterSendingAndReceiving]; 

El cambio más importante fue probablemente volviendo "NO" si no he encontrado mi controlador. La primera recepción fue, por cierto, el mensaje de descubrimiento en sí. Y cuando leo atentamente el archivo AsyncUdpSocket.h, devuelvo "NO" cuando no está ayudando un paquete que está buscando.

También tenga en cuenta que estoy usando ARC en mi código, pero compilé AsyncUdpSocket sin compatibilidad con 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

Estoy utilizando el enfoque descrito anteriormente, para descubrir una cámara de acción sony. En la línea [ssdpSock bindToPort: 1900 error: & socketError] aparece en el depurador CFSocketSetAddress listen failure: 102, sin embargo, todo está bien, el descubrimiento ocurre con éxito. ¿Qué diablos significa este fracaso? 102 No lo sé. Alguien tiene alguna idea? PD: Si profundizo un poco más, la línea donde ocurre es CFSocketError error = CFSocketSetAddress (theSocket4, (__bridge CFDataRef) address4); El valor de error es kCFSocketSuccess –