2010-07-07 55 views
7

我需要能夠發送UDP消息,並且還需要接收一個消息才能從iPhone上發現網絡上的SSDP設備。iPhone上的SSDP

我知道我需要將數據包發送到多播地址和我的HTTP請求需要看起來像這樣:

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

從閱讀看來我可以做到這一切與CFNetwork的和文檔儘管閱讀(並重新閱讀文檔),我正在努力開始。任何人都可以推薦和教程或代碼片段讓我在最初的學習駝峯?

我已經得到了CFNetwork的編程指南:

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

和Beej指南網絡編程使用Internet套接字:

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

感謝

戴夫

P.S.

我無法在這個實例中使用任何第三方庫和框架。

回答

2

好的,終於做到了。在公共領域找到一個名爲AsyncUdpSocket的公共領域的類(感謝Chris),它允許您創建一個UDP套接字,然後您可以打開廣播並加入多播地址。

有一個不錯的sendData方法,完成添加到運行循環,以防止阻塞。

希望有所幫助。

戴夫

4

我已經爲我的應用程序SSDP搜索下面的代碼:

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

它使用CocoaAsyncSocketAsyncUdpSocket

+4

嗨Savvybud,看起來不錯,但從我的頭頂(這是前一陣子我做到了這一點)我認爲你的問題在於bindToPort。我很確定這是返回消息將被髮送的端口,不應該是1900,因爲這是爲多播保留的。如果你設置爲零,那麼系統將分配一個,它應該工作。 sendData看起來很好。 – 2011-01-28 07:42:58

+0

Magic Bullet戴夫,你是男人! – savvybud 2011-01-30 02:51:36

4

我已經成功地使用AsyncUdpSocket來運行SSDP發現並找到控制器。這裏是我的代碼片段:

初始化和設置插座:

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

注意第一行註釋掉。我在AsyncUdpSocket forums上發現了一些重複的問題。我不認爲我面對他們,但我無論如何都做到了。

我添加錯誤檢查,這是有用的,因爲在我的調試,我不關閉套接字和我開始插槽設置故障:

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

通知我不得不超時所做的更改。然後最後做了接收設置,並關閉了套接字。請注意套接字關閉。由於我在自己的課上,當我運行這個 - 上面的代碼不適合我。

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





    [ssdpSock closeAfterSendingAndReceiving]; 

如果我沒有找到我的控制器,最重要的變化可能是返回「否」。第一次接收是偶然發現的消息本身回來。當我仔細閱讀AsyncUdpSocket.h文件時 - 當它不是你正在尋求幫助的數據包時返回「NO」。

另請注意,我在我的代碼中使用ARC,但我編譯了沒有ARC支持的AsyncUdpSocket。

-(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

我正在使用上述方法,來發現一個索尼動作凸輪。在調試器上出現[ssdpSock bindToPort:1900錯誤:&socketError] CFSocketSetAddress監聽失敗:102,但是一切正常,發現成功。到底意味着什麼失敗:102我不知道。任何想法?如果我挖得更深一點,它發生的線是 CFSocketError error = CFSocketSetAddress(theSocket4,(__bridge CFDataRef)address4); 錯誤值是kCFSocketSuccess – 2015-08-20 15:35:28