On 08.01.2013, at 18:45, Richard Frith-Macdonald <rich...@tiptree.demon.co.uk> 
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

_______________________________________________
Gnustep-dev mailing list
Gnustep-dev@gnu.org
https://lists.gnu.org/mailman/listinfo/gnustep-dev

Reply via email to