Reputation: 144
I am trying to couple 2 devices with NSNetService - Device A publishes the service and Device B can browse it and establish a connection. Yesterday I noticed a pretty nasty issue though.
First time I start the service on Device A and try to open the input/output streams everything works as intended. If I then quit the app on Device A and re-open it, the service gets created ( because netServiceDidPublish gets called ) but when I try opening the streams again I get the following Error Domain=NSPOSIXErrorDomain Code=61 "The operation couldn’t be completed. Connection refused. I can then wait a little bit and try opening the app again and streams get opened again as intended.
I thought it had to do with the fact that I am not closing the streams when I am quitting my app. That's why I tried closing the streams in -(void)applicationWillTerminate
. The method responsible for closing gets called but the next time I start the app I get the same error messages.
I doodled with CocoaEcho sample code provided by Apple and I can't find any major difference. Or I might be wrong.
Worth mentioning that I created a singleton class for the service publishing. I don't think this should matter but one can never know. Below you can find some of the code I am using for service publishing, stream opening and stream closing.
Open service:
-(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];
}
}
}
Service Did Publish:
-(void)netServiceDidPublish:(NSNetService *)sender {
NSLog(@"Service published on port %li", [sender port]);
if(![self openStreams]) {
NSLog(@"Could not open streams");
}
}
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;
}
Close streams
-(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;
}
Hope this is enough. Thanks in advance
Upvotes: 2
Views: 3488
Reputation: 1847
Each time that you launch your app, do you call -(void)startServiceWithName:(NSString*)name withType:(NSString*)type
?
I would recommend closing the streams each time before you call -(void)startServiceWithName:(NSString*)name withType:(NSString*)type
.
For instance:
[self.inStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[inStream release];
inStream = nil;
[self.outStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[outStream release];
outStream = nil;
[self startServiceWithName:someName withType:someType];
Upvotes: 0