Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS NSStream tcp server client can't communicate

I have an issue with the development of a tcp server/client in objective c with Bonjour.

On the server side I open correctly the streams and I use the handleEvent function to send and receive data. But I don't know what is the proper way to send and receive data. I read this excellent post : Correct way to send data through a socket with NSOutputStream So I use a packet queued system to send data :

    switch(eventCode) {

    case NSStreamEventOpenCompleted: {
        NSLog(@"Complete");

    } break;

    case NSStreamEventHasSpaceAvailable: {
        if (stream == _outputStream)
            [self _sendData];
    } break;

...

- (void)_sendData {
flag_canSendDirectly = NO;
NSData *data = [_dataWriteQueue lastObject];
if (data == nil) {
    flag_canSendDirectly = YES;
    return;
}
uint8_t *readBytes = (uint8_t *)[data bytes];
readBytes += currentDataOffset;
NSUInteger dataLength = [data length];
NSUInteger lengthOfDataToWrite = (dataLength - currentDataOffset >= 1024) ? 1024 : (dataLength - currentDataOffset);
NSInteger bytesWritten = [_outputStream write:readBytes maxLength:lengthOfDataToWrite];
currentDataOffset += bytesWritten;
if (bytesWritten > 0) {
    self.currentDataOffset += bytesWritten;
    if (self.currentDataOffset == dataLength) {
        [self.dataWriteQueue removeLastObject];
        self.currentDataOffset = 0;
    }
}

}

. So basically i just send separate my data on many packets. But I don't see how to reconstruct the data on the client side. And I think i didn't correctly understood the NSStreamEventHasBytesAvailable event. Because here I send many packets but this event on the client side is call only once. And when I reconstruct the data from the buffer the data appears to be corrupted. I would really appreciate if someone can clarify all this, the documentation is not really clear on this point (or maybe I miss a point ..) .

        case NSStreamEventHasBytesAvailable: {
        if (stream == _inputStream)
        {
            //read data
            uint8_t buffer[1024];
            int len;
            while ([_inputStream hasBytesAvailable])
            {
                len = [_inputStream read:buffer maxLength:sizeof(buffer)];
                if (len > 0)
                {
                    NSString *output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSUTF8StringEncoding];
                    //NSData *theData = [[NSData alloc] initWithBytes:buffer length:len];
                    UnitySendMessage("AppleBonjour_UnityNetworkManager(Clone)", "OnLocalClientReceiveMessageFromServer", [output cStringUsingEncoding:NSUTF8StringEncoding]);
                }
            }
        }
like image 297
thegrandwaazoo Avatar asked Nov 13 '15 13:11

thegrandwaazoo


1 Answers

It seems, that you use two variables currentDataOffset -- an instance variable and a property -- for the same purpose. If you indeed need both of them, you should set 0 to currentDataOffset as well. But I think the fragment should look like:

readBytes += currentDataOffset;
NSUInteger dataLength = [data length];
NSUInteger lengthOfDataToWrite = MIN(dataLength - currentDataOffset, 1024);
NSInteger bytesWritten = [_outputStream write:readBytes maxLength:lengthOfDataToWrite];
if (bytesWritten > 0) {
    currentDataOffset += bytesWritten;
    if (currentDataOffset == dataLength) {
        [self.dataWriteQueue removeLastObject];
        currentDataOffset = 0;
    }
}
like image 57
tonso Avatar answered Sep 30 '22 21:09

tonso