CocoaAsyncSocket и чтение данных из сокета - PullRequest
5 голосов
/ 22 июля 2011

На моем сервере на основе TCP-сокета я отправляю пакеты через поток, где пакеты состоят из заголовка, указывающего количество байтов в пакете, за которым следует это количество байтов. Для тех, кто знаком с Erlang, я просто устанавливаю параметр {package, 4}. Со стороны iOS у меня есть код, который выглядит следующим образом, при условии, что я хочу выяснить размер потока для этого сообщения:

[asyncSocket readDataToLength:4 withTimeout:-1 tag:HEADER_TAG];

Это прекрасно работает, и вызывается следующий обратный вызов метода делегата:

onSocket:didReadData:withTag:

Я полагаю, что следующий логический шаг - выяснить размер потока, и я делаю это с помощью:

  UInt32 readLength;
  [data getBytes:&readLength length:4];
  readLength = ntohl(readLength);

После жесткого кодирования строки из 12 байтов на стороне сервера readLength действительно читает также и на клиенте 12, так что пока все хорошо. Я продолжаю со следующим:

 [sock readDataToLength:readLength withTimeout:1 tag:MESSAGE_TAG];

В этот момент обратный вызов onSocket:didReadData:withTag: больше не вызывается. Вместо этого происходят тайм-ауты при чтении, возможно, из-за того, что я не обработал чтение правильно, вызывается этот метод делегата:

- (NSTimeInterval)onSocket:(AsyncSocket *)sock shouldTimeoutReadWithTag:(long)tag elapsed:(NSTimeInterval)elapsed bytesDone:(NSUInteger)length 

итак, сервер отправляет 16 байтов, 4-байтовый заголовок и 12-байтовый двоичный поток.

Я уверен, что ошибка в том, как я использую CocoaAsyncSocket. Как правильно читать остаток потока после того, как я выясню его размер?

** ОБНОВЛЕНИЕ **

Я сменил клиента, и теперь он работает. Проблема в том, что я не понимаю смысла readDataToLength с новым решением. Вот что я изменил в первоначальном прочтении:

[socket readDataWithTimeout:-1 tag:HEADER_TAG];

Теперь в моем обратном вызове я просто делаю следующее:

- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
    if (tag == HEADER_TAG) {
        UInt32 readLength;
        [data getBytes:&readLength length:4];
        readLength = ntohl(readLength);
        int offset = 4;
        NSRange range = NSMakeRange(offset, readLength);
        char buffer[readLength];
        [data getBytes:&buffer range:range];
        NSLog(@"buffer %s", buffer);
        //[sock readDataToLength:readLength withTimeout:1 tag:MESSAGE_TAG];
    } else if (tag == MESSAGE_TAG) {
        //[sock readDataToLength:4 withTimeout:1 tag:HEADER_TAG];
    }

}

Так что все приходит как одна атомная полезная нагрузка. Возможно, это из-за того, как работает Erlang {package, 4}. Я надеюсь, что это так. Иначе какой смысл в readDataToLength? нет способа заранее узнать длину сообщения на клиенте, так в чем же хороший вариант использования этого метода?

1 Ответ

1 голос
/ 22 июля 2011

Полагаю, это зависит от того, как вы отправляете со стороны Эрланга.Опция {packet, 4} будет отправлять каждый пакет данных с 4-байтовой длиной префиксом к нему.Каждая операция отправки в Erlang приведет к отправке одного пакета с префиксом его длины (максимальный размер для длины 4, например, составляет 2 Гб).Соответствующая часть документации Erlang предназначена для установки параметров сокета с помощью inet:setopts/2.

Я предполагаю, что данные - это общее количество накопленных данных, прочитанных из сокета до сих пор.Если эти данные содержат весь ваш пакет, это нормально.Но если нет, вы можете продолжить заблокированное чтение из сокета, используя readDataToLength с оставшимися данными.

...