Как я должен пометить конец TCP-пакета?

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

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

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

Ответы

Ответ 1

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

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

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

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

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

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

Ответ 2

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

Ответ 3

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

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

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

Ответ 4

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

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

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

Ответ 5

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

Ответ 6

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

Это больше, чем HMAC, если ваш трафик зашифрован.