Типичной ошибкой среди программистов сетевых приложений начала 80-х, разрабатывающих код на рабочих станциях Sun (Motorola 68000 с обратным порядком байтов), было забыть вызвать одну из указанных четырех функций. На этих рабочих станциях программы работали нормально, но при переходе на машины с прямым порядком байтов они переставали работать.
3.5. Функции управления байтами
Существует две группы функций, работающих с многобайтовыми полями без преобразования данных и без интерпретации их в качестве строк языка С с завершающим нулем. Они необходимы нам при обработке структур адресов сокетов, поскольку такие поля этих структур, как IP-адреса, могут содержать нулевые байты, но при этом не являются строками С. Строки с завершающим
нулем обрабатываются функциями языка С, имена которых начинаются с аббревиатуры
str
. Эти функции подключаются с помощью файла
<string.h>
.
Первая группа функций, названия которых начинаются с
b
(от слова «byte» — «байт»), взяты из реализации 4.2BSD и все еще предоставляются практически любой системой, поддерживающей функции сокетов. Вторая группа функций, названия которых начинаются с
mem
(от слова «memory» — память), взяты из стандарта ANSI С и доступны в любой системе, обеспечивающей поддержку библиотеки ANSI С.
Сначала мы представим функции, которые берут начало от реализации Беркли, хотя в книге мы будем использовать только одну из них —
bzero
. (Дело в том, что она имеет только два аргумента и ее проще запомнить, чем функцию
memset
с тремя аргументами, как объяснялось в разделе 1.2.) Две другие функции,
bcopy
и
bcmp
, могут встретиться вам в существующих приложениях.
Возвращает: 0 в случае равенства, ненулевое значение в случае неравенства
ПРИМЕЧАНИЕ
Мы впервые встречаемся со спецификатором const. В приведенном примере он служит признаком того, что значения, на которые указывает указатель, то есть src, ptr1 и ptr2, не изменяются функцией. Другими словами, область памяти, на которую указывает указатель со спецификатором const, считывается функцией, но не изменяется.
Функция
bzero
обнуляет заданное число байтов в указанной области памяти. Мы часто используем эту функцию для инициализации структуры адреса сокета нулевым значением. Функция
bcopy
копирует заданное число байтов из источника в место назначения. Функция
bcmp
сравнивает две произвольных последовательности байтов и возвращает нулевое значение, если две байтовых строки идентичны, и ненулевое — в противном случае.
Возвращает: 0 в случае равенства, значение <0 или >0 в случае неравенства (см. текст)
Функция
memset
присваивает заданному числу байтов значение с. Функция
memcpy
аналогична функции
bcopy
, но имеет другой порядок двух аргументов. Функция
bcopy
корректно обрабатывает перекрывающиеся
поля, в то время как поведение функции
memcpy
не определено, если источник и место назначения перекрываются. В случае перекрывания полей должна использоваться функция ANSI С
memmove
(упражнение 30.3).
ПРИМЕЧАНИЕ
Чтобы запомнить порядок аргументов функции memcpy, подумайте о том, что он совпадает с порядком аргументов в операторе присваивания (справа — оригинал, слева — копия).
dest = src;
Последним аргументом этой функции (как и всех ANSI-функций memXXX) всегда является длина области памяти.
Функция
memcmp
сравнивает две произвольных последовательности байтов и возвращает нуль, если они идентичны. В противном случае знак возвращаемого значения определяется знаком разности между первыми несовпадающими байтами, на которые указывают ptr1и ptr2. Предполагается, что сравниваемые байты принадлежат к типу
unsigned char
.
3.6. Функции inet_aton, inet_addr и inet_ntoa
Существует две группы функций преобразования адресов, которые мы рассматриваем в этом и следующем разделах. Они выполняют преобразование адресов Интернета из строк ASCII (удобных для человеческого восприятия) в двоичные значения с сетевым порядком байтов (эти значения хранятся в структурах адресов сокетов).
1. Функции
inet_aton
,
inet_ntoa
и
inet_addr
преобразуют адрес IPv4 из точечно-десятичной записи (например, 206.168.112.96) в 32-разрядное двоичное значение в сетевом порядке байтов. Возможно, вы встретите эти функции в многочисленных существующих программах.
2. Более новые функции
inet_pton
и
inet_ntop
работают и с адресами IPv4, и с адресами IPv6. Эти функции, описываемые в следующем разделе, мы используем в книге.
#include <arpa/inet.h>
int inet_aton(const char * strptr, struct in_addr * addrptr);
Возвращает: 1, если строка преобразована успешно, 0 в случае ошибки
in_addr_t inet_addr(const char * strptr);
Возвращает: 32-разрядный адрес IPv4 в сетевом порядке байтов: INADDR_NONE в случае ошибки
char *inet_ntoa(struct in_addr inaddr);
Возвращает: указатель на строку с адресом в точечно-десятичной записи
Первая из названных функций,
inet_aton
, преобразует строку, на которую указывает
strptr
, в 32-разрядное двоичное число, записанное в сетевом порядке байтов, передаваемое через указатель
addrptr
. При успешном выполнении возвращаемое значение равно 1, иначе возвращается нуль.
ПРИМЕЧАНИЕ
Функция inet_aton обладает одним недокументированным свойством: если addrptr — пустой указатель (null pointer), функция все равно выполняет проверку допустимости адреса, содержащегося во входной строке, но не сохраняет результата.
Функция
inet_addr
выполняет то же преобразование, возвращая в качестве значения 32-разрядное двоичное число в сетевом порядке байтов. Проблема при использовании этой функции состоит в том, что все 2 32возможных двоичных значений являются действительными IP-адресами (от 0.0.0.0 до 255.255.255.255), но в случае возникновения ошибки функция возвращает константу
INADDR_NONE
(обычно представленную двоичным числом, состоящим из 32 бит, установленных в единицу). Это означает, что точечно-десятичная запись 255.255.255.255 (ограниченный адрес для широковещательной передачи IPv4, см. раздел 18.2) не может быть обработана этой функцией, поскольку ее двоичное значение выглядит как указание на сбой при выполнении функции.