NSNetServiceBrowser не находит службу

Я попытался написать клиентское (iPad)/серверное (iMac) приложение на основе примера CocoaEcho. Мой первый простой пример сработал, но после добавления дополнительных функций клиент не может найти сервер.

После запуска сервера запускаю клиент, как в локальной сети. Клиент начинает поиск сервисов и получает сообщение «netServiceBrowserWillSearch:» для своего браузера, но после этого ничего не происходит. Повторный запуск поиска служб приводит к сообщению «didNotsearch:» с ошибкой -72003, 10 (браузер все еще занят поиском).

1) Я проверил, доступен ли сервер с помощью приложения WiTap. Там клиент и сервер правильно соединяются.

2) Проверил, публикует ли сервер сервис с "dns-sd -B _cocoaecho", он обнаружен.

3) Объект nsnetservicebrowser в клиентском приложении объявляется свойством, поэтому проблем с областью действия быть не должно. Я также проверил в отладчике, он все еще там....

Мой код:

Клиент:

    @interface MySocketClient : UIResponder <NSNetServiceBrowserDelegate, NSStreamDelegate>
    {
    ...
    NSNetService * myServer;
    NSString* nextMsg;
    }
    @property (nonatomic, strong, readwrite) NSMutableArray *       services;           // of NSNetService

    @property (nonatomic, strong, readwrite) NSNetServiceBrowser *  serviceBrowser;
    @property (nonatomic, strong, readwrite) NSInputStream *        inputStream;
    @property (nonatomic, strong, readwrite) NSOutputStream *       outputStream;
    @property (nonatomic, strong, readwrite) NSMutableData *        inputBuffer;
    @property (nonatomic, strong, readwrite) NSMutableData *        outputBuffer;

    ....

    -(void) setup{
    ...
    self.serviceBrowser = [[NSNetServiceBrowser alloc] init];
    self.services = [[NSMutableArray alloc] init];
    [self.serviceBrowser setDelegate:self];
    [self.serviceBrowser searchForServicesOfType:@"_cocoaecho._tcp." inDomain:@"local."];
    }

    - (void)netServiceBrowser:(NSNetServiceBrowser *)netServiceBrowser didNotSearch:(NSDictionary *)errorInfo
   {
    NSLog(@"%@", errorInfo);
    }

// Sent when browsing begins
- (void)netServiceBrowserWillSearch:(NSNetServiceBrowser *)browser
{
    NSLog(@"will search \n");
}

// Sent when browsing stops
- (void)netServiceBrowserDidStopSearch:(NSNetServiceBrowser *)browser
{
    NSLog(@"stopped search \n");
}

//We broadcast the willChangeValueForKey: and didChangeValueForKey: for the NSTableView binding to work.
- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didFindService:(NSNetService *)aNetService moreComing:(BOOL)moreComing {
#pragma unused(aNetServiceBrowser)
#pragma unused(moreComing)
     NSLog(@"found a service \n");
    if (![self.services containsObject:aNetService]) {
        [self willChangeValueForKey:@"services"];
        [self.services addObject:aNetService];
        [self didChangeValueForKey:@"services"];
        myServer = aNetService;
    }
}

- (void)netServiceBrowser:(NSNetServiceBrowser *)aNetServiceBrowser didRemoveService:(NSNetService *)aNetService moreComing:(BOOL)moreComing {
#pragma unused(aNetServiceBrowser)
#pragma unused(moreComing)
    if ([self.services containsObject:aNetService]) {
        [self willChangeValueForKey:@"services"];
        [self.services removeObject:aNetService];
        [self didChangeValueForKey:@"services"];
    }
}

И Сервер:

    - (BOOL)start {
    assert(_ipv4socket == NULL && _ipv6socket == NULL);       // don't call -start twice!

    CFSocketContext socketCtxt = {0, (__bridge void *) self, NULL, NULL, NULL};
    _ipv4socket = CFSocketCreate(kCFAllocatorDefault, AF_INET,  SOCK_STREAM, 0, kCFSocketAcceptCallBack, &EchoServerAcceptCallBack, &socketCtxt);
    _ipv6socket = CFSocketCreate(kCFAllocatorDefault, AF_INET6, SOCK_STREAM, 0, kCFSocketAcceptCallBack, &EchoServerAcceptCallBack, &socketCtxt);

    if (NULL == _ipv4socket || NULL == _ipv6socket) {
        [self stop];
        return NO;
    }

    static const int yes = 1;
    (void) setsockopt(CFSocketGetNative(_ipv4socket), SOL_SOCKET, SO_REUSEADDR, (const void *) &yes, sizeof(yes));
    (void) setsockopt(CFSocketGetNative(_ipv6socket), SOL_SOCKET, SO_REUSEADDR, (const void *) &yes, sizeof(yes));

    // Set up the IPv4 listening socket; port is 0, which will cause the kernel to choose a port for us.
    struct sockaddr_in addr4;
    memset(&addr4, 0, sizeof(addr4));
    addr4.sin_len = sizeof(addr4);
    addr4.sin_family = AF_INET;
    addr4.sin_port = htons(0);
    addr4.sin_addr.s_addr = htonl(INADDR_ANY);
    if (kCFSocketSuccess != CFSocketSetAddress(_ipv4socket, (__bridge CFDataRef) [NSData dataWithBytes:&addr4 length:sizeof(addr4)])) {
        [self stop];
        return NO;
    }

    // Now that the IPv4 binding was successful, we get the port number
    // -- we will need it for the IPv6 listening socket and for the NSNetService.
    NSData *addr = (__bridge_transfer NSData *)CFSocketCopyAddress(_ipv4socket);
    assert([addr length] == sizeof(struct sockaddr_in));
    self.port = ntohs(((const struct sockaddr_in *)[addr bytes])->sin_port);

    // Set up the IPv6 listening socket.
    struct sockaddr_in6 addr6;
    memset(&addr6, 0, sizeof(addr6));
    addr6.sin6_len = sizeof(addr6);
    addr6.sin6_family = AF_INET6;
    addr6.sin6_port = htons(self.port);
    memcpy(&(addr6.sin6_addr), &in6addr_any, sizeof(addr6.sin6_addr));
    if (kCFSocketSuccess != CFSocketSetAddress(_ipv6socket, (__bridge CFDataRef) [NSData dataWithBytes:&addr6 length:sizeof(addr6)])) {
        [self stop];
        return NO;
    }

    // Set up the run loop sources for the sockets.
    CFRunLoopSourceRef source4 = CFSocketCreateRunLoopSource(kCFAllocatorDefault, _ipv4socket, 0);
    CFRunLoopAddSource(CFRunLoopGetCurrent(), source4, kCFRunLoopCommonModes);
    CFRelease(source4);

    CFRunLoopSourceRef source6 = CFSocketCreateRunLoopSource(kCFAllocatorDefault, _ipv6socket, 0);
    CFRunLoopAddSource(CFRunLoopGetCurrent(), source6, kCFRunLoopCommonModes);
    CFRelease(source6);

    assert(self.port > 0 && self.port < 65536);
    self.netService = [[NSNetService alloc] initWithDomain:@"local." type:@"_cocoaecho._tcp." name:@"" port:(int) self.port];
    [self.netService publishWithOptions:0];

    return YES;
}

person user2508733    schedule 21.06.2013    source источник


Ответы (2)


Я просто постоянно получал эту ошибку -72003, если только я не отключился и снова не подключился (даже в первый раз). Что приводит к этому решению:

private let serviceBrowser = NSNetServiceBrowser()

serviceBrowser.stop()
serviceBrowser.searchForServicesOfType(TYPE, inDomain: DOMAIN)

Я не знаю, почему это работает, но я больше не получаю ошибку.

person Daniel Ryan    schedule 18.01.2016

У меня была аналогичная проблема. Мой код успешно зарегистрировал NSNetService и запустил NSNetServiceBrowser, но не смог -resolveWithTimeout другие устройства. Странно, но иногда работало, иногда нет, а иногда работало асимметрично.

После интенсивной отладки я могу дать вам несколько советов для проверки:

  1. Установите браузер Bonjour на рабочий стол. Отсоедините сетевой кабель и проверьте, подключены ли вы к той же точке доступа Wi-Fi, что и мобильные устройства. Здесь вы должны увидеть то же состояние службы, что и на мобильных устройствах.

  2. Попробуйте с другой точкой доступа Wi-Fi. Странно, но мой основной WiFi работал плохо. После того, как я переключился на другой, он работал как шарм, используя тот же код. Попробуйте отключить Wi-Fi от Интернета для проверки.

  3. Вы можете добавить некоторые сохранения (или присвоить статическую переменную) объектам, возвращаемым из API (например, NSNetService). ARC может молча освободить место, если решит, что объект больше не нужен. Это помогло мне в некоторых тестах.

person vedrano    schedule 23.06.2013