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.
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