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;
}
2 ответа
Я просто получал эту ошибку -72003 все время, пока я не отключился и снова не подключился (даже в первый раз). Что приводит к этому решению:
private let serviceBrowser = NSNetServiceBrowser()
serviceBrowser.stop()
serviceBrowser.searchForServicesOfType(TYPE, inDomain: DOMAIN)
Я не знаю, почему это работает, но я больше не получаю ошибку.
У меня была похожая проблема. Мой код успешно зарегистрировал NSNetService и запустил NSNetServiceBrowser, но не смог - разрешить с другими устройствами. Странно, но иногда работало, иногда нет, а иногда работало асимметрично.
После интенсивной отладки я могу дать вам несколько советов для проверки:
Установите Bonjour Browser на рабочий стол. Подключите сетевой кабель и проверьте, подключены ли вы к той же точке доступа WiFi, что и мобильные устройства. Здесь вы должны увидеть то же состояние обслуживания, что и мобильные устройства.
Попробуйте с другой точкой доступа WiFi. Странно, но мой основной WiFi работал плохо. После того, как я переключился на другой, он работал как шарм, используя тот же код. Попробуйте отключить WiFi от Интернета для тестирования.
Вы можете добавить некоторые сохранения (или присвоить статической переменной) к объектам, возвращаемым из API (например, NSNetService). ARC может выполнить delock без вывода сообщений, если решит, что объект больше не нужен. Это помогло мне в некоторых тестах.