通过单线程设计读取和写入NSStream输入/输出句柄

时间:2015-06-23 05:51:15

标签: ios multithreading nsstream

我想创建一个应由单个线程处理的tcp监听器类,即所有io操作都应由单个线程执行。

当消息到达inputStream时触发事件,多个线程可以向侦听器线程添加任务以写入输出流。

我从代码开始,但坚持理解runloop概念。

我的问题是我可以将一个任务添加到runloop,比如输入源(这里是socket)警告runloop吗?

如果我从runloop中删除inputresources,关联的线程是否会终止其执行?如果没有,我怎么能终止线程的执行。

我试过的代码

#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];

请建议一个好的设计。提前谢谢。

1 个答案:

答案 0 :(得分:0)

https://github.com/robbiehanson/CocoaAsyncSocket

使用GCDAsyncSocket,您可以指定要使用的线程。

您可以在自述文件和https://github.com/robbiehanson/CocoaAsyncSocket/wiki

中找到有关如何处理套接字的大量信息