Прокладывать или не прокладывать - создание протокола связи

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

Например: я хочу отправить заголовок сообщения, состоящий из 3-байтового поля, за которым следует 1-байтовое поле заполнения для 32-битного выравнивания. Затем я отправлю данные сообщения.

В этом случае получатель просто возьмет 3 байта из потока и отбросит байт заполнения. А затем начните читать данные сообщения. Насколько я понимаю, он не будет хранить 3 байта и данные сообщения так, как ему хочется. Весь смысл выравнивания байтов заключается в том, чтобы они были извлечены эффективным образом. Но если ретривер не заботится о заполнении, как оно будет эффективно извлечено?

Без заполнения извлекатель просто берет 3 байта заголовка из потока, а затем берет байты данных. Поскольку ретривер хранит эти байты так, как хочет, какая разница, выполнено заполнение или нет?

Может быть, я упускаю момент заполнения.

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

Пожалуйста, дайте мне знать, что вы, ребята, думаете.

Спасибо, джбу


person jbu    schedule 17.06.2009    source источник


Ответы (5)


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

Если сообщение представляет собой поток байтов, например xml, то заполнение не принесет вам много пользы.

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

person SingleNegationElimination    schedule 17.06.2009
comment
+1 использовать текст для удобства чтения, отладки, ведения журнала, расширения и т. д. и/или сжатый текст для минимизации размера; двоичный формат вполне может быть преждевременной оптимизацией. Однако двоичный формат может оптимизировать использование ЦП и памяти, что было важным соображением для TCP (и может быть или не быть важным для собственного протокола/приложения). - person ChrisW; 17.06.2009

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

Если я получатель, я могу передать буфер (т. е. массив байтов) драйверу протокола (т. е. стеку TCP) и сказать: «Верните мне это, когда в нем будут данные».

То, что я (приложение) получаю, это массив байтов, который содержит данные. Используя трюки в стиле C, такие как «приведение» и т. Д., Я могу обрабатывать части этого массива, как если бы это были слова и двойные слова (а не только байты) ... при условии, что они соответствующим образом выровнены (где может быть заполнение обязательный).

Вот пример оператора, который считывает DWORD из смещения в байтовом буфере:

DWORD getDword(const byte* buffer)
{
  //we want the DWORD which starts at byte-offset 8
  buffer += 8;
  //dereference as if it were pointing to a DWORD
  //(this would fail on some machines if the pointer
  //weren't pointing to a DWORD-aligned boundary)
  return *((DWORD*)buffer);
}

Вот соответствующая функция в сборке Intel; обратите внимание, что это один код операции, то есть довольно эффективный способ доступа к данным, более эффективный, чем чтение и накопление отдельных байтов:

mov eax,DWORD PTR [esi+8]
person ChrisW    schedule 17.06.2009

Одна из причин рассмотреть заполнение — если вы планируете со временем расширять свой протокол. Часть заполнения может быть преднамеренно отложена для будущего назначения.

Еще одна причина рассмотреть заполнение — это сэкономить пару битов в полях длины. т.е. всегда кратное 4 или 8 экономит 2 или 3 бита поля длины.

person Case Larsen    schedule 17.06.2009

Еще одна веская причина, по которой TCP имеет заполнение (которое, вероятно, не относится к вам), заключается в том, что он позволяет выделенному сетевому оборудованию легко отделять данные от заголовка. Поскольку данные всегда начинаются с 32-битной границы, легче отделить заголовок от данных при маршрутизации пакета.

person marcush    schedule 17.06.2009

Если у вас есть 3-байтовый заголовок и выровняйте его по 4 байтам, то назначьте неиспользуемый байт как «зарезервированный для будущего использования» и потребуйте, чтобы биты были равны нулю (отклоняя сообщения, где они не так искажены). Это оставляет вам некоторую расширяемость. Или вы можете решить использовать байт в качестве номера версии - сначала ноль, а затем увеличивать его, если (когда) вы вносите несовместимые изменения в протокол. Не допускайте, чтобы значение было «неопределенным» и «все равно»; вы никогда не сможете использовать его, если вы начнете таким образом.

person Jonathan Leffler    schedule 17.06.2009