Как я должен отметить конец пакета TCP? - PullRequest
17 голосов
/ 05 марта 2010

В клиент-серверном приложении, если текстовые данные различной длины будут отправляться взад и вперед между клиентом и сервером, как я должен отметить конец отправляемого пакета? Например, когда сервер получает пакетные данные от клиента, как сервер узнает, что клиентский пакет полностью получен?

Чаще ли сообщать серверу полную длину пакета, который он собирается получить, перед данными или чтобы что-то помечало конец пакета?

Некоторые отправляемые данные будут иметь длину всего несколько символов, а некоторые могут быть тысячи символов.

Ответы [ 6 ]

30 голосов
/ 06 марта 2010

TCP обеспечивает непрерывный поток данных. TCP реализован с использованием пакетов, но весь смысл TCP в том, чтобы скрыть их.

Думайте об этом, как будто это стена, на которой вы хотите рисовать. Стена сделана из кирпича. Кирпичи склеиваются вместе с раствором, и наносится штукатурка, чтобы поверхность стены стала гладкой. Кирпичи - это IP-пакеты, TCP - штукатурка.

Итак, теперь у вас есть гладкий оштукатуренный TCP-туннель, и вы хотите добавить в него некоторую структуру. Вы хотите нарисовать прямоугольники, чтобы ваши рисунки были отделены друг от друга. Это то, что вы хотите сделать: добавить немного «административной» структуры (рамки вокруг чертежей) к вашим данным.

Во многих протоколах используется концепция packet, представляющая собой набор данных, начинающийся с административного заголовка фиксированного формата. Заголовок содержит достаточно информации, чтобы решить, где заканчивается пакет; например, он включает в себя длину пакета. HTTP делает это с заголовком Content-Length или (с HTTP / 1.1) с помощью "кодированной передачи", где данные разбиваются на один или несколько мини-пакетов, каждый из которых имеет простой заголовок, состоящий ровно из мини-пакета. указание длины.

Другим способом является специальная последовательность-терминатор, которая не может отображаться в «обычных данных». Если ваши данные являются текстовыми, то вы можете использовать байт нулевого значения в качестве терминатора.

Еще один способ - использовать самоданные данные. Это данные, структурированные таким образом, что в любой момент вы можете узнать, достигнут ли конец элемента. Например, данные XML организованы в виде вложенных пар маркеров, таких как <foo>...</foo>. Когда достигнут маркер конца (</foo>), вы знаете, что элемент завершен.

3 голосов
/ 05 марта 2010

Структурируйте свой пакет так, чтобы он включал поле длины в начале.

2 голосов
/ 06 марта 2010

Если отправитель знает длину, то отправитель должен указать длину впереди как поле фиксированного размера, а затем данные переменного размера.

Преимущество перед хвостовым маркером состоит в том, что приемник может оптимизировать ожидаемый объем данных, например, выделить буфер правильного размера. Например, хранилище по протоколам TCP / IP имеет ту же проблему, что и вы по протоколу TCP / IP. В этих случаях заголовки обеспечивают длину ожидаемых данных.

Позже, в будущем, вы можете найти другие биты для вставки в ваш «заголовок». Вы будете рады, что у вас есть некоторая структура для развития вашего собственного протокола уровня 5.

1 голос
/ 26 ноября 2016

Остерегайтесь мусора, если вы кодируете длину в начале. Например, если вы используете 4 двоичных байта по длине и какой-то внешний зонд отправляет HTTP-запрос, вы, скорее всего, получите огромное количество и будете ждать вечно (не говоря уже о выделении буфера, который может привести к сбою вашей программы). Я отправляю длину дважды в каждую функцию и сравниваю их (например, ~ len и len xor 0x139AF321). Вы также должны установить максимум в случае, если кто-то активно пытается завершить работу вашей программы. Если я получаю неправильную длину, я просто закрываю соединение.

Это сверх HMAC, если ваш трафик зашифрован.

1 голос
/ 08 марта 2010

Если вы чувствуете себя особенно смелым, вы можете использовать SCTP сокеты вместо TCP-сокетов.

1 голос
/ 05 марта 2010

Возьмите свои реплики из HTTP.

Используйте последовательность символов-терминаторов, или укажите длину где-нибудь в заголовке сообщения, или используйте умную комбинацию обоих.

Как HTTP делает:заголовки заканчиваются на CR-LF-CR-LF.Если за заголовками есть данные, длина данных указана в одном из заголовков.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...