2

I am working on a very simple application to discover a device using SSDP and I am trying to find the easiest way to parse the response from this command. I am trying to avoid having to do a bunch of NSString or regular expressions manipulations.

I have tried the following two approaches:

Approach 1: Using GCDAsyncUdpSocket, I am able to successfully send the discovery command and get the following response:


HTTP/1.1 200 OK
Cache-Control: max-age=300
ST: roku:ecp
USN: uuid:roku:ecp:1234567890
Ext:
Server: Roku UPnP/1.0 MiniUPnPd/1.4
Location: http://192.168.XX.XX:8060/


This looks like a regular HTTP response, but using GCDAsyncUdpSocket, I am getting the response as an NSData object, which I can easily convert to an NSString. However, what would be ideal is to somehow cast this to an NSHTTPURLResponse and then use its methods to get the field values. Any idea if this can be done?

Approach 2: I have tried using a regular NSURLRequest to try to send this command and then I would be able to get an NSHTTPURLResponse back. However, I keep on getting an error because the SSDP discovery command requires me to send this request to port 1900. I use the following code to send the "HTTP" request, I know it is not strictly HTTP, but I thought it may be an easier way to send this UDP command as the requirements look very similar to HTTP.

NSURL *url = [NSURL URLWithString:@"http://239.255.255.250:1900"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
                            cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];


[request setHTTPMethod:@"M-SEARCH *"];
[request setValue:@"239.255.255.250:1900" forHTTPHeaderField:@"Host"];
[request setValue:@"\"ssdp:discover\"" forHTTPHeaderField:@"Man"];
[request setValue:@"roku:ecp" forHTTPHeaderField:@"ST"];

NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:request delegate:self startImmediately:YES];
    if (connection)
    {
        NSLog(@"Connection success!");
    }
    else
    {
        NSLog(@"Connection failed!");   
    }

When I do this, the connection is successful, but I get the following error in the didFailWithError delegate for NSURLConnection:

failed Error Domain=NSPOSIXErrorDomain Code=47 "The operation couldn’t be completed. Address family not supported by protocol family" UserInfo=0x8875940 {NSErrorFailingURLKey=http://239.255.255.250:1900/, NSErrorFailingURLStringKey=http://239.255.255.250:1900/}

This error only happens if I use port 1900, if I leave this out or use another more HTTP friendly port such as 8080, then this works, but obviously the device I am trying to discover does not respond correctly unless it gets the request in port 1900.

Thanks for any help you can provide.

4

1 回答 1

3

端口 1900 对于 SSDP 是固定的。所有 UPnP 设备都固定在此端口上侦听,并且连接节点期望这样做。你不能改变它。“开箱即用”是 UPnP 设计目标的一部分。此外,我的 Cocoa 专业知识非常有限,但我认为这NSHTTPURLResponse不会让你的事情变得更简单。[NSHTTPURLResponse allHeaderFields]return NSDictionary,这意味着您不再知道标头字段的原始顺序是什么。你需要知道接下来会发生什么,Ext:然后是一个元标题。

我建议要么自己解析响应,这不应该比一个循环复杂得多,按行分隔响应,然后按:. 或者,不要尝试使用自己的 SSDP 握手,而是使用现成的 Cocoish 库,例如 Upnpx、Cyber​​link 或 Platinum。对于发现阶段,它可能感觉像是不恰当的重型火炮,但我想知道在那之后你会对设备做什么,而不是实际尝试在设备上调用一些操作。

于 2012-11-21T09:33:43.030 回答