• в отличие от датаграммных сокетов UNIX-домена, UDP-сокеты не являются надежными: пакеты могут теряться, дублироваться или приходить не в том порядке, в котором они были отправлены;
• отправка пакетов через датаграммный сокет UNIX-домена блокируется, если очередь данных принимающего сокета заполнена. Для сравнения: если UDP-датаграмма грозит переполнить очередь получателя, она просто автоматически отклоняется.
IP-адреса и номера портов являются целыми числами. Одна из проблем, с которой можно столкнуться при передаче этих значений по сети, такова: различные аппаратные платформы хранят байты целого числа в разном порядке (при условии, что их больше одного). Как показано на рис. 55.1, существуют платформы, где целое значение начинается со старшего байта (то есть с наименьшего адреса); иногда их называют
Рис. 55.1.
Поскольку номера портов и IP-адреса приходится передавать между разными узлами сети, каждый из которых должен понимать их значение, возникает необходимость в некоем стандартном порядке следования байтов. Этот порядок называется
Позже в данной главе мы рассмотрим различные функции для приведения имен сетевых узлов (например, www.kernel.org) и служб (например, http) к соответствующему цифровому представлению. Обычно они возвращают целые числа в сетевом порядке следования байтов, которые можно скопировать непосредственно в подходящие поля структуры для хранения адреса сокета.
Но иногда с целочисленными константами для IP-адресов и номеров портов приходится работать напрямую. Например, чтобы явно указать номер порта в коде нашей программы, получить его в качестве аргумента командной строки или воспользоваться константами INADDR_ANY и INADDR_LOOPBACK при определении IPv4-адреса. В языке C эти значения представлены в том формате, который используется на текущем компьютере. Прежде чем задействовать их в структуре для хранения адреса сокета, следует привести их к сетевому порядку следования байтов.
Для преобразования целых чисел между стандартным сетевым форматом и представлением, применяемым на текущем компьютере, предусмотрены функции tons(), htonl(), ntohs() и ntohl() (обычно они реализованы в виде макросов).
#include
uint16_t htons(uint16_t
Возвращает значение host_uint16, приведенное к сетевому порядку следования байтов
uint32_t htonl(uint32_t
Возвращает значение host_uint32, приведенное к сетевому порядку следования байтов
uint16_t ntohs(uint16_t
Возвращает значение net_uint16, приведенное к порядку следования байтов, которое применяется на текущем компьютере
uint32_t ntohl(uint32_t
Возвращает значение net_uint32, приведенное к порядку следования байтов, используемое на текущем компьютере
Когда-то эти функции имели прототипы следующего вида:
unsigned long htonl(unsigned long hostlong);
Это объясняет происхождение их имен: в данном случае htonl расшифровывается как
Строго говоря, реальная необходимость в этих четырех функциях возникает только в системах, где локальный порядок следования байтов отличается от сетевого. Тем не менее их следует использовать в любом случае, чтобы обеспечить портируемость программ между разными аппаратными архитектурами. В системах, где локальный порядок следования байтов совпадает с сетевым, приведенные функции просто возвращают передаваемые им аргументы.