Domanda

I am trying to create a simple multiplayer turn-based game between iPhones. Right now all I want to do is pass in some string to my method, and have the method send the string through the NSOutputStream. I think I have properly connected my NSNetServices using NSNetServiceBrowser. Once they connect, my NSNetServiceDelegate has netService:didAcceptConnectionWithInputStream:outputStream: called, which should give me my i/o NSStream pair. My method looks like this:

-(void)netService:(NSNetService *)sender didAcceptConnectionWithInputStream:(NSInputStream *)inputStream outputStream:(NSOutputStream *)outputStream{
    [self.myNet getInputStream:&inputStream outputStream:&outputStream];
    self.inStream = inputStream;
    self.outStream = outputStream;
    [self.inStream setDelegate:self];
    [self.inStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [self.inStream open];
}

I think I have correctly set up NSInputStream. I also have a delegate for NSStream which is implementing stream:handleEvent:

It looks like this:

-(void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode{
    NSInputStream *inStream = (NSInputStream *)aStream;
    BOOL shouldClose = NO;
    switch(eventCode) {
        case  NSStreamEventEndEncountered:
            shouldClose = YES;
            // If all data hasn't been read, fall through to the "has bytes" event
            if(![inStream hasBytesAvailable]) break;
        case NSStreamEventHasBytesAvailable: ; // We need a semicolon here before we can declare local variables
            uint8_t *buffer;
            NSUInteger length;
            BOOL freeBuffer = NO;
            // The stream has data. Try to get its internal buffer instead of creating one
            if(![inStream getBuffer:&buffer length:&length]) {
                // The stream couldn't provide its internal buffer. We have to make one ourselves
                buffer = malloc(BUFFER_LEN * sizeof(uint8_t));
                freeBuffer = YES;
                NSInteger result = [inStream read:buffer maxLength:BUFFER_LEN];
                if(result < 0) {
                    // error copying to buffer
                    break;
                }
                length = result;
            }
            // length bytes of data in buffer
            if(freeBuffer) free(buffer);
            break;
        case NSStreamEventErrorOccurred:
            // some other error
            shouldClose = YES;
            break;
        case NSStreamEventHasSpaceAvailable:
            break;
        case NSStreamEventNone:
            break;
        case NSStreamEventOpenCompleted:
            break;
    }
    if(shouldClose){
        [inStream close];
    }
}

I took that code from: this page. In that code, aStream should be self.inStream. I have looked at pages describing what to do for NSOutputStream, but none of them seem to be geared at a beginner like me. I have a few questions. Firstly, how do I set up a method that I pass the data in (NSData or maybe an NSString) and it sends it out through self.outStream. I would prefer an answer that explains the code, rather than just giving it to me. Secondly, should I open both of my streams in netService:didAcceptConnectionWithInputStream:outputStream:, and should I also scheduleInRunLoop the NSOutputStreamself.outStream`. Finally, am I doing everything wrong?

Thanks for your answers. Also this is my first question, so any constructive criticism is welcomed.

È stato utile?

Soluzione

To write to output stream, check stream has space available and write data using

- (NSInteger)write:(const uint8_t *)buffer maxLength:(NSUInteger)length

So, code may be like following.

if ( self.outStream.hasSpaceAvailable ) [ self.outStream write:... maxLength: ];

If output stream doesn't have space available, later

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

method of the delegate of output stream would be called with eventCode = NSStreamEventHasSpaceAvailable.

You should open output stream and schedule it in netService:didAcceptConnectionWithInputStream:outputStream or when you receive NSStreamEventOpenCompleted of input stream. Both are OK.

If you don't want writing block thread, you need to prepare queue.

So code is like following

    NSMutableData*  uQueue;
    NSInputStream*  uIStream;
    NSOutputStream* uOStream;

    :
    :
    :

    uIStream.delegate = self;
    uOStream.delegate = self;

    [ uIStream scheduleInRunLoop:NSRunLoop.currentRunLoop forMode:NSDefaultRunLoopMode ];
    [ uOStream scheduleInRunLoop:NSRunLoop.currentRunLoop forMode:NSDefaultRunLoopMode ];

    [ uIStream open ];
    [ uOStream open ];

    uQueue = NSMutableData.data;


    :
    :
    :

-   (void)
Send
{   if ( uQueue.length )
    {   NSInteger wLength = [ uOStream write:(const uint8_t*)uQueue.bytes maxLength:uQueue.length ];
        if ( wLength > 0 ) [ uQueue replaceBytesInRange:NSMakeRange( 0, wLength ) withBytes:NULL length:0 ];
    }
}

-   (void)
Write:(NSData*)p
{   [ uQueue appendData:p ];
    if ( uOStream.hasSpaceAvailable ) [ self Send ];
}


-   (void)
stream:(NSStream*)pS
handleEvent:(NSStreamEvent)p
{   switch( p )
    {

    :
    :
    :

    case NSStreamEventHasSpaceAvailable:
        [ self Send ];
        break;
    }
}


Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top