我正在尝试将 2 个设备与 NSNetService 耦合 -设备 A发布服务,设备 B可以浏览它并建立连接。昨天我注意到一个非常讨厌的问题。
我第一次在设备 A上启动服务并尝试打开输入/输出流,一切都按预期工作。如果我然后退出设备 A上的应用程序并重新打开它,则会创建服务(因为 netServiceDidPublish 被调用)但是当我再次尝试打开流时,我得到以下错误 Domain=NSPOSIXErrorDomain Code=61“操作无法完成。连接被拒绝。然后我可以稍等片刻,然后尝试再次打开应用程序,然后流会按预期再次打开。
我认为这与我退出应用程序时没有关闭流的事实有关。这就是为什么我尝试关闭-(void)applicationWillTerminate
. 负责关闭的方法被调用,但下次我启动应用程序时,我会收到相同的错误消息。
我用 Apple 提供的 CocoaEcho 示例代码涂鸦,但找不到任何主要区别。或者我可能错了。
值得一提的是,我为服务发布创建了一个单例类。我认为这无关紧要,但永远不会知道。您可以在下面找到我用于服务发布、流打开和流关闭的一些代码。
开通服务:
-(void)startServiceWithName:(NSString*)name withType:(NSString*)type {
// init the socket
if(_socket) {
// socket initialized
addr = (struct sockaddr*)[[_socket address] bytes];
if (addr->sa_family==AF_INET) {
// IPV4
port = ntohs( ((struct sockaddr_in *)addr)->sin_port );
}
if (addr->sa_family==AF_INET6) {
// IPV6
port = ntohs( ((struct sockaddr_in6 *)addr)->sin6_port );
}
} else {
// socket nil
_socket = nil;
NSLog(@"Socket init failed. Can't handle");
}
// init the service
if(_socket) {
// we have a socket
_service = [[NSNetService alloc] initWithDomain:@"local."
type:type
name:name
port:port];
if (_service) {
[_service setDelegate:self];
[_service publish];
}
}
}
服务已发布:
-(void)netServiceDidPublish:(NSNetService *)sender {
NSLog(@"Service published on port %li", [sender port]);
if(![self openStreams]) {
NSLog(@"Could not open streams");
}
}
打开流
-(BOOL)openStreams {
NSInputStream *is;
NSOutputStream *os;
if ([_service getInputStream:&is outputStream:&os]) {
_inputStream = is;
_outputStream = os;
[_inputStream setDelegate:self];
[_outputStream setDelegate:self];
[_inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[_outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[_inputStream open];
[_outputStream open];
return YES;
}
return NO;
}
关闭流
-(void)closeStreams {
[_inputStream setDelegate:nil];
[_outputStream setDelegate:nil];
[_inputStream close];
[_outputStream close];
[_inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[_outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
_inputStream = nil;
_outputStream = nil;
}
希望这已经足够了。提前致谢