gnustep-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: "Modern" server socket programming?


From: Marcus Müller
Subject: Re: "Modern" server socket programming?
Date: Wed, 9 Jan 2013 15:02:04 +0100


On 08.01.2013, at 18:45, Richard Frith-Macdonald <address@hidden> wrote:

I don't have any demo/example code for a server, but to show it, I chopped out the key bits of a larger program:

PS. using a server socket is exactly like using a client NSStream with the exception of two method calls:
1. to create the listening stream/socket
2. to accept an incoming connection (when the listening socket is readable), creating new in/out streams
This is a direct reflection of the way standard unix/bsd sockets worK, so if you know unix socket programming (or cocoa streams programming) it should be really easy.

Just for reference, here is a complete (and tested) example I wrote for my pet project:

- (void)setupListenerSocket {
self->inputStreams = [NSMutableArray array];
self->serverStream = [GSServerStream serverStreamToAddr:@"" port:0];
NSAssert(self->serverStream, @"Could not open random port?");
[self->serverStream setDelegate:self];
[self->serverStream open];
[self->serverStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}

- (void)stream:(NSStream* )_stream handleEvent:(NSStreamEvent)_event
{
if (_stream == self->serverStream) {
switch (_event) {
case NSStreamEventHasBytesAvailable: {
NSInputStream  *is;
NSOutputStream *os;

[self->serverStream acceptWithInputStream:&is outputStream:&os];
[self->inputStreams addObject:is];
[is setDelegate:self];
[is open];
[is scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
break;
}
case NSStreamEventNone:
case NSStreamEventOpenCompleted:
case NSStreamEventHasSpaceAvailable:
case NSStreamEventEndEncountered:
break;
default:
NSLog(@"Ignoring event: %ld", _event);
break;
}
}
else {
NSInputStream *is = (NSInputStream *)_stream;

switch (_event) {
case NSStreamEventHasBytesAvailable: {
NSMutableData *d = [NSMutableData dataWithLength:128];
NSUInteger len = [is read:(uint8_t *)[d bytes] maxLength:[d length]];
if (len > 0) {
((char *)[d bytes])[len + 1] = '\0';
NSString *cmd = [NSString stringWithUTF8String:(const char *)[d bytes]];
NSLog(@"read %ld bytes, string '%@'", len, cmd);
}
break;
}
case NSStreamEventEndEncountered: {
[self->inputStreams removeObject:is];
break;
}
case NSStreamEventNone:
case NSStreamEventOpenCompleted:
case NSStreamEventHasSpaceAvailable:
break;
default:
NSLog(@"Ignoring event: %ld", _event);
break;
}
}
}

Please note that the actual reading code misses several checks and is pretty naive, but it serves the purpose of demonstrating the mechanism.

As a bottom line, I'll have to say that I dislike the structure of the above code. As Richard already said, it's logical to expand the NSStream functionality to server-side as it is done in GNUstep, because it doesn't introduce new API and even the handling doesn't change (you just have to sort out the context the NSStreamEventHasBytesAvailable is currently in as is done above when you have just one object acting as a delegate for everything related to NSStream events). But this dislike is not related to GNUstep, but more to the fact that the -stream:handleEvent: method feels like a C-function, not like a proper method. Personally, I'd prefer separate delegate methods for any relevant event - just as it's modelled in the ULINetSocket class. Another missed opportunity by Apple. ;-)


Cheers,


  Marcus


-- 
Marcus Müller  .  .  .  http://www.mulle-kybernetik.com/znek/



Attachment: smime.p7s
Description: S/MIME cryptographic signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]