yacana
yacana

Reputation: 144

NSStream - The operation couldn’t be completed. Connection refused

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

Answers (1)

yeesterbunny
yeesterbunny

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

Related Questions