Могу ли я безопасно игнорировать порядок байтов в сети?

24

Я разрабатываю приложение сервер-клиент, в котором клиент будет работать в Windows, а сервер, вероятно, в Linux. Возможно, я позже перенесу клиента на Mac и Linux, но пока нет.

Все домашние компьютеры в наши дни работают с прямым порядком байтов. Некоторое время я гуглил, но не смог найти список устройств, работающих на старшем порядке. Насколько я знаю, некоторые чипы Motorola по-прежнему используют телефоны с прямым порядком байтов и, возможно, некоторые телефоны (я не планирую переносить приложение на смартфоны, поэтому для меня это не имеет значения). Итак, зачем мне переставлять байты каждого целого, каждого короткого, каждого числа с плавающей запятой, двойного числа и т. Д. Для чтения и записи , когда я уже знаю, что и сервер, и клиент работают с прямым порядком байтов?

Это просто ненужная работа. Итак, мой вопрос: могу ли я безопасно игнорировать порядок байтов и просто отправлять данные с прямым порядком байтов? Каковы недостатки?

tkausl
источник
4
Как машины узнают, получают ли они данные с прямым порядком байтов вместо обычных / стандартных данных с прямым порядком байтов?
Ixrec
2
Вы должны различать метаданные, которые требуются сетевым протоколом, и полезную нагрузку, которая представляет собой просто набор неинтерпретируемых байтов для всех, кроме вашего кода. Я надеюсь, что вы не катите свой собственный сетевой стек. Следовательно, я предполагаю, что вопрос только о полезной нагрузке, правильно?
2
@delnan да, речь идет только о полезной нагрузке. Я, конечно, все еще буду говорить в порядке сетевых байтов с самим сетевым стеком.
tkausl
3
Просто мысль на стороне: действительно ли вам нужно работать на уровне абстракции, где проблема порядка байтов? Возможно, стоит рассмотреть возможность использования протоколов, для которых существуют соответствующие библиотеки, которые инкапсулируют весь этот низкоуровневый «беспорядок». Тогда у вас также есть дополнительный бонус, что добавление дополнительных клиентов может быть сделано намного проще.
godfatherofpolka
1
@tkausl Еще две мысли на стороне: как правило, IO очень медленный по сравнению с вычислениями, поэтому любые издержки, возникающие при работе на более высоком уровне абстракции, скорее всего незначительны. Может даже случиться, что некоторые библиотеки превосходят управляемые вручную реализации благодаря умному пулу ресурсов и асинхронной обработке и т. Д. Итак, я сначала тщательно оценил бы существующие решения. Кроме того, учитывая ваше описание, я бы также уделил немного внимания масштабируемости, а не производительности, здесь вы могли бы снова извлечь выгоду из использования протоколов более высокого уровня.
godfatherofpolka

Ответы:

29

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

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

Существует стандартный порядок байтов в сети. Это big-endian, но ничто не говорит о том, что вы должны соблюдать его при разработке протокола. Если вы заранее знаете, что большинство систем, в которых работает ваш код, будут иметь непосредственный порядок и производительность критична, объявите «стандартный порядок байтов tkausl» и продолжайте. Там, где вы обычно звоните, htons()чтобы расположить вещи в нужном вам порядке, напишите макрос с именем, htots()который условно компилируется на архитектурах с прямым порядком байтов и выполняет реорганизацию на старшем порядке.

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

Blrfl
источник
10
Формулировка when designing your protocolважна, потому что она также неявно говорит, что эта опция существует только при разработке нового протокола, а не при реализации какого-либо существующего протокола. И упоминание о необходимости htots(и действительно целого семейства функций) также ясно дает понять, что выбор другого порядка байтов - это не то, что нужно для упрощения кода, но может сделать его немного быстрее.
Касперд
4
Есть (нестандартные , но очень часто в эти дни) функции htole32(), htole16(), le16toh()и т.д., доступные функции , а также. Файл, который нужно включить, чтобы объявить их, к сожалению, даже менее стандартный: <endian.h>или <sys/types.h>зависит от платформы.
Торек
Этот ответ хорош, но я думаю, что предположение о том, что производительность может быть критической в ​​данном случае, скорее всего, ошибочное, основанное больше на суевериях, чем на фактах.
Док Браун
1
@DocBrown: Я всегда хотел бы отметить, что протокол X поддерживает выбор собственного порядка байтов в течение 30 лет, и, несмотря на ограниченность ресурсов, никто никогда не жаловался, что это проблема.
Blrfl
7

Это твой протокол.

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

Это означает накладные расходы. Теперь вы должны как-то отметить свой порядок байтов. Сделай это, и я смогу прочитать это на чем угодно.

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

candied_orange
источник
6

Итак, мой вопрос: могу ли я безопасно игнорировать порядок байтов и просто отправлять данные с прямым порядком байтов?

Есть две интерпретации этого:

  • Если вы разрабатываете свои приложения / протоколы всегда 1 посыла прямой порядок байтов, то вы не игнорируя порядок байтов.

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

    Это "безопасно" 2 ? Это вам судить! Но, безусловно, существуют распространенные аппаратные платформы, в которых используется порядок байтов с прямым порядком байтов, порядок байтов с прямым порядком байтов или ... порядок байтов

    Ссылка:

Каковы недостатки?

Очевидный недостаток игнорирования функции endaness заключается в том, что если вам / вашим пользователям необходимо запускать ваши приложения / протокол между платформами с различной собственной функцией endianess, то у вас есть проблема. Приложения будут ломаться, и вам нужно будет изменить их, чтобы решить проблему. И решать проблемы совместимости версий и так далее.

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


1 - Всегда ... в том числе на платформах, которые изначально являются старшими.

2 - Действительно, что означает «безопасный»? Если вы просите нас предсказать будущее направление аппаратных платформ ... Я боюсь, что это не объективно подотчетно.

Стивен С
источник
3

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

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

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

gnasher729
источник
3

Стандартный сетевой стек BSD в C имеет hton/ ntohfunction ( network-to-host/ host-to-network), которая расширяется до no-ops на сетевых машинах (с прямым порядком байтов). Вам понадобятся ваши собственные аналоги для сценария, в котором сетевой порядок байтов имеет младший порядок.

Это надежный способ сделать это.

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

PSkocik
источник
3

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

  1. BSON
  2. Буферы протокола
  3. Capn Proto

См. Https://en.wikipedia.org/wiki/Comparison_of_data_serialization_formats для получения подробной информации о различных форматах, некоторые из которых имеют порядковые номера, а некоторые имеют порядковые номера.

Нет ничего плохого в использовании протокола, основанного на порядковых числах. Большая машина с порядком байтов так же способна читать порядковые номера, как и маленькая машина с порядком байтов. Многие люди сделали это специально, чтобы избежать дополнительных вычислительных затрат при декодировании чисел с прямым порядком байтов на машинах с прямым порядком байтов.

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

Уинстон Эверт
источник
2

Одним из примеров системы с прямым порядком байтов является MIPS, используемый в маршрутизаторах. И ARM, и MIPS имеют возможность переключения с прямым порядком байтов, но часто MIPS - это порядковый номер с прямым порядком байтов, поскольку он упрощает сетевое оборудование (наиболее важной частью слова является та, которую вы получаете первой, и может принять решение о маршрутизации, прежде чем вы получите остальные слово, а не необходимость буферизовать все слово).

Таким образом, это зависит от того, что вы подразумеваете под «Linux», но если вы когда-нибудь захотите запустить свое серверное приложение на небольшой системе, например на маршрутизаторе с OpenWRT, то вам, возможно, придется подумать о поддержке с прямым порядком байтов.

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

user1908704
источник
0

Я не думаю, что какой-либо из ответов достаточно точен. Согласно Википедии, порядковый номер - это порядок байтов, составляющих слово.

Давайте возьмем 4 байта и интерпретируем их как int. В одной системе с прямым порядком байтов байты будут интерпретироваться справа налево, и наоборот в большой системе байтов. Очевидно, что важно договориться о том, с какой стороны интерпретировать int.

Давайте немного уменьшим масштаб современных сетевых протоколов, которые могут использовать json или xml. Ни один из этих форматов не будет передавать int как 4 байта. Они будут передавать данные в виде текста, который будет получен как int на принимающей стороне.

Так что в конце концов порядок байтов не имеет значения при использовании json или xml. Нам все еще нужно использовать big endian для заголовков tcp, поэтому он называется сетевым порядком байтов, но большинству программистов не нужно ежедневно связываться с ними.

В настоящее время наиболее широко используемым кодированием в большинстве случаев является utf-8, который также может быть невосприимчивым к проблемам, связанным с порядком байтов .

Так что я бы сказал, да. Можно безопасно игнорировать порядок байтов при использовании текстовых форматов, передаваемых с использованием utf-8.

Эсбен Сков Педерсен
источник
два отрицательных голоса и без комментариев. Отлично.
Эсбен Сков Педерсен
1
Я не был downvoter, но этот ответ, кажется, игнорирует / отклоняет совершенно правильный вопрос. То, что некоторые протоколы основаны на тексте, не означает, что все протоколы должны быть.
Питер Грин
2
Я проголосовал за это, потому что это касается того факта, что формат полезной нагрузки не имеет ничего общего с базовыми протоколами. Некоторые люди просто любят копаться в выдуманных проблемах.
Зденек
0

Похоже, что большие системы порядка байтов находятся на выходе. Во многих традиционных Unix-системах использовался порядок байтов, но в течение многих лет они находились в упадке в пользу Linux на x86.

рука является би-эндианом, но вариант с прямым порядком байтов редко встречается.

mips существует в обоих вариантах. На самом деле вариант с прямым порядком байтов чаще всего встречается в сетевых приложениях (по историческим причинам в интернет-протоколах обычно используется порядок с прямым порядком байтов).

ppc был традиционно с прямым порядком байтов, некоторые части поддерживали оба порядка байтов, но IBM, похоже, теперь использует режим с прямым порядком байтов для 64-битных ppc (недавно они перенесли порты ppc64el в Debian и Ubuntu).

sparc обычно с прямым порядком байтов, но, похоже, снова в упадке.

Если вы реализуете существующий протокол, то, очевидно, вы должны следовать его спецификациям. Если вы хотите, чтобы IETF благословил ваш новый протокол, вероятно, будет проще использовать big endian, потому что это то, что они уже используют в своих существующих протоколах, но IMO для нового «протоколдного» дизайна «с нуля», little endian - это путь.

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

Питер Грин
источник