2013-06-21 5 views
1

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

После запуска сервера я запускаю клиент, как в локальной сети. Клиент начинает поиск служб и получает сообщение «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; 
} 

ответ

0

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

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

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

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

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

1

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

private let serviceBrowser = NSNetServiceBrowser() 

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

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

+1

имел ту же проблему, это помогает. благодаря! – spinalwrap