Reading from and writing to NSStream in/out handle by single thread design

237 views Asked by At

I would like to make a tcp listener class that should handled by a single thread ie all io operations should be carried out by a single thread.

Trigger an event when a message is arrived to inputStream and multiple thread can add a task to listener thread for writing to the outputstream.

I am started with the code, but stuck on understanding the runloop concepts.

My questions is can I add a task to runloop like inputsources(here socket) alerting the runloop?

If I remove the inputresources from the runloop, does the associated thread terminates its execution? if no how can I terminate thread's execution.

Code I have tried

#import "TCPControler.h"

@implementation TCPListener
{
    NSInputStream *in;

    NSOutputStream *out;

    NSString *ipAddress;

    int portNum;

}

-(id) initWithAddress:(NSString *) ip portNumber: (int) port{
    self=[super init];
    if(self){
        ipAddress=ip;
        portNum=port;
    }
    return self;
}


-(void) start{
    dispatch_queue_t q=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
    dispatch_async(q, ^{ [self runEventLoop];});
}

-(void) runEventLoop{
    CFReadStreamRef readStream;
    CFWriteStreamRef writeStream;
    CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)@"10.2.2.63", 2208, &readStream, &writeStream);
    in = (__bridge NSInputStream *)(readStream);
    out = (__bridge NSOutputStream *)writeStream;
    [in setDelegate:self];
    [out setDelegate:self];
    [in scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [out scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [in open];
    [out open];
    [[NSRunLoop currentRunLoop]run];
}


-(void) stop{
    NSLog(@"Closing streams.");

    [in close];
    [out close];

    [in removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [out removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];


    [in setDelegate:nil];
    [out setDelegate:nil];


    in = nil;
    out = nil;
}

-(void) onRead{

}

-(void) onConnected{

}

-(void) onDisconnected{

}

-(void) write:(NSString *) data{

}

-(void) stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode{

    @try {


    switch (eventCode) {

        case NSStreamEventOpenCompleted:
            NSLog(@"Event fired NSStreamEventOpenCompleted %d",aStream==in);
            break;

        case NSStreamEventHasBytesAvailable:
            NSLog(@"Event fired NSStreamEventHasBytesAvailable %d",aStream==in);


            if(aStream == in) {
                NSLog(@"inputStream is ready.");

                uint8_t buf[1024];
                NSInteger len=0;

                len = [in read:buf maxLength:1024];

                if(len > 0) {
                    NSMutableData* data=[[NSMutableData alloc] initWithLength:0];

                    [data appendBytes: (const void *)buf length:len];

                    NSString *s = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
                    NSLog(@" %@",s);


                }
            }

            break;

        case NSStreamEventNone:
            NSLog(@"Event fired NSStreamEventNone %d",aStream==in);
            break;

        case NSStreamEventHasSpaceAvailable:
            NSLog(@"Event fired NSStreamEventHasSpaceAvailable %d",aStream==in);
            break;

        case NSStreamEventErrorOccurred:
            NSLog(@"Event fired NSStreamEventErrorOccurred %d",aStream==in);
            break;

        case NSStreamEventEndEncountered:
            NSLog(@"Event fired NSStreamEventEndEncountered %d",aStream==in);
            [self stop];
            break;

        default:
            NSLog(@"Event fired ");
            break;
    }
    }
    @catch (NSException *exception) {
         NSLog(@"Event fired %@",exception);
    }
    @finally {

    }
}


@end

TCPControler *con=[[TCPControler alloc] initWithAddress:@"10.2.2.63" portNumber:80];
[con start];

Please suggest a good design. Thanks in advance.

1

There are 1 answers

1
GaétanZ On

https://github.com/robbiehanson/CocoaAsyncSocket

Using GCDAsyncSocket, you can specify the thread you want to use.

You can find a lot of informations on how sockets are handled in the readme file and in https://github.com/robbiehanson/CocoaAsyncSocket/wiki