Клиент TCP-сервера iOS NSStream не может обмениваться данными

У меня проблема с разработкой tcp-сервера/клиента в задаче c с Bonjour.

На стороне сервера я правильно открываю потоки и использую функцию handleEvent для отправки и получения данных. Но я не знаю, как правильно отправлять и получать данные. Я прочитал этот отличный пост: Правильный способ отправки данных через сокет с NSOutputStream Поэтому я использую систему очереди пакетов для отправки данных:

    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;
    }
}

}

. Так что в основном я просто отправляю свои данные по многим пакетам. Но я не вижу, как восстановить данные на стороне клиента. И я думаю, что неправильно понял событие NSStreamEventHasBytesAvailable. Потому что здесь я отправляю много пакетов, но это событие на стороне клиента вызывается только один раз. И когда я восстанавливаю данные из буфера, данные кажутся поврежденными. Я был бы очень признателен, если бы кто-то мог все это прояснить, документация не очень ясна в этом вопросе (или, может быть, я что-то упускаю ..).

        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]);
                }
            }
        }

person thegrandwaazoo    schedule 13.11.2015    source источник
comment
Вы пробовали простой тест? Отправить одну короткую строку. Что вы получаете на выходе своей переменной, когда делаете это? мимо; не обязательно должен быть один вызов байтов, доступных для каждой отправки, они будут объединены, если прибудут вовремя, и одно чтение получит их все. Пожалуйста, попробуйте этот тест и расскажите нам, что у вас получилось.   -  person john elemans    schedule 18.11.2015
comment
О, я забыл еще одну вещь; Вы можете протестировать приемник с помощью простой программы TCP, такой как telnet. Просто подключитесь к своему порту и введите текст. Если код получателя работает, вы должны получить свой текст напрямую.   -  person john elemans    schedule 21.11.2015
comment
Хорошо, простая строка сработала. Поэтому, если я отправлю строку больше, чем буфер, мне просто нужно реконструировать ее каждый раз, когда вызывается NSStreamEventHasBytesAvailable. Но как я могу получить уведомление, когда строка полностью отправлена?   -  person thegrandwaazoo    schedule 23.11.2015
comment
Вы не можете. Поток есть поток. Вы должны закодировать конец сообщения в самом потоке. Когда получатель обрабатывает входящие байты, он должен искать «маркер конца сообщения». В зависимости от отправителя и поскольку получатель может быть занят, вы должны быть готовы обработать блок, в котором может быть конец сообщения, а также несколько байтов, начало следующего сообщения.   -  person john elemans    schedule 23.11.2015


Ответы (1)


Похоже, вы используете две переменные currentDataOffset -- переменную экземпляра и свойство -- для одной и той же цели. Если вам действительно нужны оба из них, вы также должны установить 0 на currentDataOffset. Но я думаю, что фрагмент должен выглядеть так:

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;
    }
}
person tonso    schedule 22.11.2015