Я обычно не люблю отвечать, когда уже есть "приличный" ответ. В этом случае я собираюсь сделать исключение, поскольку информация, которую я добавил к этим ответам, неверно истолковывается.
INADDR_ANY
определяется как адрес IPv4 с нулевыми битами, 0.0.0.0
или 0x00000000
. Вызов htonl()
для этого значения приведет к тому же значению, ноль. Поэтому вызов htonl()
для этого постоянного значения не является технически необходимым.
INADDR_ALL
определяется как однобитовый адрес IPv4, 255.255.255.255
или 0xFFFFFFFF
. Вызов htonl()
с INADDR_ALL
вернет INADDR_ALL
. Опять же, вызов htonl()
не является технически необходимым.
Другой константой, определенной в заголовочных файлах, является INADDR_LOOPBACK
, определяемый как 127.0.0.1
или 0x7F000001
. Этот адрес задается в порядке сетевых байтов и не может быть передан в интерфейс сокетов без htonl()
. Вы должны использовать htonl()
с этой константой.
Некоторые могут предположить, что согласованность и читаемость кода требуют, чтобы программисты использовали htonl()
для любой константы с именем INADDR_*
- потому что это требуется для некоторых из них. Эти постеры неправильны.
Пример, приведенный в этой теме:
if (some_condition)
sa.s_addr = htonl(INADDR_LOOPBACK);
else
sa.s_addr = INADDR_ANY;
Цитата из "Джона Цвинка":
«Если бы я просматривал этот код, я бы сразу спросил, почему одна из констант применила htonl, а другая нет. И я сообщаю об этом как об ошибке, независимо от того, получилось ли у меня« внутреннее знание »о том, что INADDR_ANY всегда О, так что конвертировать это нельзя, и я думаю (и надеюсь), что многие другие сопровождающие сделают то же самое ».
Если бы я получал такой отчет об ошибке, я бы немедленно его выбросил. Этот процесс сэкономил бы мне много времени, предоставляя отчеты об ошибках от людей, у которых нет «базового минимального знания», что INADDR_ANY
всегда равно 0. (Предполагая, что знание значений INADDR_ANY
и др. Каким-то образом нарушает инкапсуляцию или что-то еще, кроме стартера - те же самые числа используются в выводе netcat
и внутри ядра. Программистам нужно знать фактические числовые значения. Люди, которые не знают, не испытывают недостатка в внутри знания, им не хватает базовых знаний о местности.)
Действительно, если у вас есть программист, поддерживающий код сокетов, и этот программист не знает битовых шаблонов INADDR_ANY и INADDR_ALL, у вас уже есть проблемы. Обертывание 0 в макросе, который возвращает 0, является типом менталитета, который является рабом бессмысленной последовательности и не уважает знание предметной области.
Ведение кода сокетов - это больше, чем просто понимание C. Если вы не понимаете разницу между INADDR_LOOPBACK
и INADDR_ANY
на уровне, совместимом с выводом netstat
, то вы опасны в этом коде и не должны меняю его.
Спорные аргументы, предложенные Цвинком в отношении ненужного использования htonl()
:
- Опытные программисты сокетов могут обидеть использование htonl, потому что они будут знать, что он ничего не делает (так как они знают значение константы наизусть).
Это соломенный аргумент, потому что у нас есть изображение, которое опытные программисты сокетов знают наизусть значение INADDR_ANY
. Это все равно что писать, что только опытный программист C знает значение NULL
наизусть. Запись «наизусть» создает впечатление, что число немного трудно запомнить, возможно, из нескольких цифр, например, 127.0.0.1
. Но нет, мы гиперболически обсуждаем сложность запоминания шаблонов, называемых «все нулевые биты» и «все одни биты».
Учитывая, что эти числовые значения появляются в выводе, например, netstat
и других системных утилит, а также учитывая, что некоторые из этих значений появляются в заголовках IP, не существует такого понятия, как компетентный программист сокетов, который не знать эти значения, наизусть или мозгом. На самом деле, попытки программирования сокетов без знания этих основ могут быть опасны для доступности сети.
- Требуется меньше печатать, чтобы опустить его.
Этот аргумент должен быть абсурдным и пренебрежительным, поэтому ему не нужно много опровергать.
- Поддельная оптимизация "производительности" (ясно, что это не имеет значения).
Трудно понять, откуда пришел этот аргумент.Это может быть попытка выдвинуть оппозицию глупые, казалось бы, аргументы.В любом случае отсутствие макроса htonl()
не влияет на производительность, если вы предоставляете константу и используете типичный компилятор C - выражения константы в любом случае сводятся к константе.
Причина не использовать htonl()
с INADDR_ANY в том, что самый опытный программист сокетов знает, что это не нужно.Более того: те программисты, которые не знают, должны учиться.С использованием htonl()
нет никаких дополнительных «затрат», проблема заключается в том, чтобы установить стандарт кодирования, который способствует игнорированию таких критически важных значений.
По определению, инкапсуляция способствует игнорированию.Именно это невежество является обычным преимуществом использования инкапсулированного интерфейса - знание дорого и конечно, поэтому инкапсуляция обычно хороша.Возникает вопрос: какие усилия в программировании лучше всего усилить с помощью инкапсуляции?Существуют ли задачи программирования, которые не выполняются при инкапсуляции?
Технически некорректно использовать htonl()
, поскольку это не влияет на это значение.Тем не менее, аргументы, которые вы должны использовать, могут вводить в заблуждение.
Есть те, кто будет утверждать, что лучше ситуация, в которой разработчику не нужно знать, что INADDR_ANY
это все нули и так далее.Эта страна невежества хуже, а не лучше.Учтите, что эти «магические значения» используются в различных интерфейсах с TCP / IP.Например, при настройке Apache, если вы хотите слушать только IPv4 (а не IPv6), вы должны указать:
Listen 0.0.0.0:80
Я столкнулся с программистами, которые ошибочно указали локальный IP-адрес вместо INADDR_ANY
(0.0.0.0) выше.Эти программисты не знают, что такое INADDR_ANY
, и, вероятно, они обертывают его в htonl()
, пока они там.Это земля абстрагирующего мышления и инкапсуляции.
Идеи «инкапсуляции» и «абстракции» были широко приняты и слишком широко применяются, но они не всегда применимы.В области адресации IPv4 эти значения констант не следует рассматривать как «абстрактные» - они преобразуются непосредственно в биты в проводе.
Моя точка зрения такова: «правильного» нет"использование INADDR_ANY
с htonl()
- оба эквивалентны.Я бы не рекомендовал принимать требование, чтобы значение использовалось каким-либо конкретным способом, потому что семейство констант INADDR_X
имеет только четыре члена, и только один из них, INADDR_LOOPBACK
имеет значение, которое отличается в зависимости от порядка следования байтов.Лучше просто знать этот факт, чем устанавливать стандарт для использования значений, который закрывает глаза на битовые комбинации значений.
Во многих других API полезно, чтобы программисты продолжали работуне зная числовых значений или битовых комбинаций констант, используемых API.В случае API сокетов эти битовые комбинации и значения используются в качестве входных данных и отображаются повсеместно.Лучше знать эти значения численно, чем тратить время на размышления об использовании на них htonl()
.
При программировании на C, особенно, большинство «использования» API-сокетов предполагает захват исходного кода другого человека,и адаптируя его.Это еще одна причина, по которой так важно знать, что такое INADDR_ANY
, прежде чем касаться строки, которая его использует.