KnigaRead.com/
KnigaRead.com » Компьютеры и Интернет » Программное обеспечение » Уильям Стивенс - UNIX: разработка сетевых приложений

Уильям Стивенс - UNIX: разработка сетевых приложений

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Уильям Стивенс, "UNIX: разработка сетевых приложений" бесплатно, без регистрации.
Перейти на страницу:

В названиях этих функций h обозначает узел, n обозначает сеть, s — тип short, l — тип long. Термины short и long являются наследием времен реализации 4.2BSD Digital VAX. Следует воспринимать s как 16-разрядное значение (например, номер порта TCP или UDP), а l — как 32-разрядное значение (например, адрес IPv4). В самом деле, в 64-разрядной системе Digital Alpha длинное целое занимает 64 разряда, а функции htonl и ntohl оперируют 32-разрядными значениями (несмотря на то, что используют тип long).

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

Мы еще вернемся к проблеме определения порядка байтов, обсуждая данные, содержащиеся в сетевом пакете, и сравнивая их с полями в заголовках протокола, в разделе 5.18 и упражнении 5.8.

Мы до сих пор не определили термин байт. Его мы будем использовать для обозначения 8 бит, поскольку практически все современные компьютерные системы используют 8-битовые байты. Однако в большинстве стандартов Интернета для обозначения 8 бит используется термин октет. Началось это на заре TCP/IP, поскольку большая часть работы выполнялась в системах типа DEC-10, в которых не применялись 8-битовые байты. Еще одно важное соглашение, принятое в стандартах Интернета, связано с порядком битов. Во многих стандартах вы можете увидеть «изображения» пакетов, подобные приведенному ниже (это первые 32 разряда заголовка IPv4 из RFC 791):

0                   1                   2                   3

0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

|Version| IHL |Type of Service|           Total Length          |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

В этом примере приведены четыре байта в том порядке, в котором они передаются по проводам. Крайний слева бит является наиболее значимым. Однако нумерация начинается с нуля, который соответствует как раз наиболее значимому биту. Вам необходимо получше ознакомиться с этой записью, чтобы не испытывать трудностей при чтении описаний протоколов в RFC.

ПРИМЕЧАНИЕ

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

3.5. Функции управления байтами

Существует две группы функций, работающих с многобайтовыми полями без преобразования данных и без интерпретации их в качестве строк языка С с завершающим нулем. Они необходимы нам при обработке структур адресов сокетов, поскольку такие поля этих структур, как IP-адреса, могут содержать нулевые байты, но при этом не являются строками С. Строки с завершающим нулем обрабатываются функциями языка С, имена которых начинаются с аббревиатуры str. Эти функции подключаются с помощью файла <string.h>.

Первая группа функций, названия которых начинаются с b (от слова «byte» — «байт»), взяты из реализации 4.2BSD и все еще предоставляются практически любой системой, поддерживающей функции сокетов. Вторая группа функций, названия которых начинаются с mem (от слова «memory» — память), взяты из стандарта ANSI С и доступны в любой системе, обеспечивающей поддержку библиотеки ANSI С.

Сначала мы представим функции, которые берут начало от реализации Беркли, хотя в книге мы будем использовать только одну из них — bzero. (Дело в том, что она имеет только два аргумента и ее проще запомнить, чем функцию memset с тремя аргументами, как объяснялось в разделе 1.2.) Две другие функции, bcopy и bcmp, могут встретиться вам в существующих приложениях.

#include <strings.h>


void bzero(void *dest, size_t nbytes);


void bcopy(const void *src, void *dest, size_t nbytes);


int bcmp(const void *ptr1, const void *ptr2, size_t nbytes);

Возвращает: 0 в случае равенства, ненулевое значение в случае неравенства

ПРИМЕЧАНИЕ

Мы впервые встречаемся со спецификатором const. В приведенном примере он служит признаком того, что значения, на которые указывает указатель, то есть src, ptr1 и ptr2, не изменяются функцией. Другими словами, область памяти, на которую указывает указатель со спецификатором const, считывается функцией, но не изменяется.

Функция bzero обнуляет заданное число байтов в указанной области памяти. Мы часто используем эту функцию для инициализации структуры адреса сокета нулевым значением. Функция bcopy копирует заданное число байтов из источника в место назначения. Функция bcmp сравнивает две произвольных последовательности байтов и возвращает нулевое значение, если две байтовых строки идентичны, и ненулевое — в противном случае.

Следующие функции являются функциями ANSI С:

#include <string.h>


void *memset(void *dest, int c, size_t len);


void *memcpy(void *dest, const void *src, size_t nbytes);


int memcmp(const void *ptr1, const void *ptr2, size_t nbytes);

Возвращает: 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), функция все равно выполняет проверку допустимости адреса, содержащегося во входной строке, но не сохраняет результата.

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*