SSDP на iPhone

Мне нужно иметь возможность отправлять UDP-сообщения, а также получать их, чтобы обнаруживать SSDP-устройства в сети с iPhone.

Я знаю, что мне нужно отправить пакет на многоадресный адрес, и мой 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

и Руководство Биджа по сетевому программированию с использованием интернет-сокетов:

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

Спасибо

Дэйв

P.S.

В этом случае я не могу использовать какие-либо сторонние библиотеки и фреймворки.


person Magic Bullet Dave    schedule 07.07.2010    source источник


Ответы (3)


Я успешно использовал AsyncUdpSocket для запуска SSDP Discovery и поиска контроллеров. Вот мои фрагменты кода:

Инициализируйте и настройте сокет:

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

Обратите внимание на первую строку, закомментированную. Я обнаружил на форумах AsyncUdpSocket некоторые проблемы с дубликатами. Я не думаю, что я столкнулся с ними, но я сделал это в любом случае.

Я добавил проверку ошибок, и это было полезно, потому что во время отладки я не закрывал сокеты, и у меня начались сбои установки сокетов:

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, мне помогло возвращение «НЕТ», когда это не тот пакет, который вы ищете.

Также обратите внимание, что я использую ARC в своем коде, но я скомпилировал AsyncUdpSocket без поддержки 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;

}
person Ashu Joshi    schedule 02.03.2012
comment
Я использую описанный выше подход, чтобы найти экшн-камеру Sony. В строке [ssdpSock bindToPort:1900 error:&socketError] появляется отладчик CFSocketSetAddress listen failure: 102, однако все ок, обнаружение происходит успешно. Что, черт возьми, означает этот провал: 102 я не знаю. Любая идея? PS: Если я копну немного глубже, строка, в которой это происходит, будет ошибкой CFSocketError = CFSocketSetAddress(theSocket4, (__bridge CFDataRef)address4); значение ошибки kCFSocketSuccess - person i-developer; 20.08.2015

У меня есть следующий код для поиска 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);}

Он использует AsyncUdpSocket из CocoaAsyncSocket.

person savvybud    schedule 27.01.2011
comment
Привет, Savvybud, выглядит нормально, но по моему мнению (это было некоторое время назад, я сделал это), я думаю, что ваша проблема связана с bindToPort. Я почти уверен, что это порт, на который будут отправляться обратные сообщения, и он не должен быть 1900, так как он зарезервирован для многоадресной рассылки. Если вы установите это значение равным нулю, система выделит единицу, и она должна работать. sendData выглядит нормально. - person Magic Bullet Dave; 28.01.2011

Хорошо, наконец сделал это. Нашел общедоступный класс (спасибо, Крис) под названием AsyncUdpSocket, который позволяет вам создать UDP-сокет, который затем можно включить вещание и присоединиться к многоадресному адресу.

Существует хороший метод sendData с добавлением в цикл выполнения для предотвращения блокировки.

Надеюсь, это поможет.

Дэйв

person Magic Bullet Dave    schedule 25.07.2010