NSOutputStream или витой реактор, объединяющий данные пакета TCP - PullRequest
0 голосов
/ 10 мая 2011

Я работаю над некоторым сетевым кодом для приложения для iPhone, которое взаимодействует с бэкэндом Python Twisted. Недавно я столкнулся с проблемой, когда кажется, что либо мой NSOutputStream удваивает полезную нагрузку при отправке, либо витой удваивает полезную нагрузку при получении.

Я использую стиль «Apple Recommended» для сокетов TCP, E.G. без опроса.

Процесс выглядит следующим образом:
КЛИЕНТ
- NSStreamEventHasSpaceAvailable: отправить пакет из X байтов данных
- NSStreamEventHasSpaceAvailable: отправить еще один пакет из Y байтов данных
SERVER
- Twisted получает пакет размером (X + Y) байтов

Я проверяю, явно ли я не отправляю данные, если состояние outputStream имеет статус «NSStreamStatusWriting». Также гарантируется, что данные не могут быть отправлены от клиента, если NSStreamEventHasSpaceAvailable не было выброшено.

Есть идеи относительно того, что может быть причиной этого удвоения / слияния полезной нагрузки? Код Twisted довольно прост, используя стандартные данные, полученные в моем протоколе:

    def dataRecieved(self, data):
        # do logic in order to decide how to handle data
        # ...
        # print of len(data) here reveals merged packet size

Код iOS также довольно стандартный:

    if (eventCode == NSStreamEventHasSpaceAvailable)
    {
        [outputStream write:[packet getData] maxLength:[packet getPacketSize]];
    }
    // [packet getData] simply returns a standard UInt8 array. 
    // [packet getPacketSize] returns the size of that array.

Когда указанный выше код iOS вызывается два раза подряд (например, отправка двух пакетов один за другим), скрученный код сообщает о размере объединенных данных.

Заранее спасибо за любые советы или предложения.

1 Ответ

1 голос
/ 10 мая 2011

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

В TCP на основе не существует предсказуемого поведениясвязь;между вами и удаленным хостом может быть любое количество маршрутизаторов, границ NAT, тупых прокси-серверов или чего-то еще, что диктует поведение, которое кажется неожиданным.byte .

Реальный мир, однако, поведение обычно довольно предсказуемо.Но не всегда, никогда в 100% случаев, и всегда с потенциалом какого-то клиента где-то с забитыми трубками.

С TCP вы, по крайней мере, гарантированы, что обычно пакетов будутполученные в порядке они отправляются, если нет ошибки.Предположим, опять же, что все точки между ними реализованы правильно или не являются вредоносными (этот последний бит означает, что вы должны предполагать, что иногда данные будут повреждены).

Даже эта гарантия мало что значит;вы можете получить первые 8 из 10 пакетов ... или вы можете получить все входящие данные только для того, чтобы обнаружить, что исходящее соединение разорвано, когда вы собираетесь отвечать ...

Итог;Ваш алгоритм буферизации с обеих сторон должен предполагать, что буфер может быть заполнен случайными пакетами, которые полностью не соответствуют размеру данных, застрявших на другой стороне.Хотя не требуется строго , ваше приложение будет лучше защищено от случайных сбоев соединения;против усеченных буферов, случайных разрывов соединений и повреждения данных.

Ранние поля длины байта и контрольные суммы - ваш друг.Предположения, вы! Hjfdahjdas8y! $ (& ($ @ # & ^ @ #) ^ &! @ # & _ [потерянное соединение]

...