Чтение онлайн

ЖАНРЫ

UNIX: разработка сетевых приложений
Шрифт:

В следующей главе мы увидим, что размер структуры адреса сокета в действительности имеет тип

socklen_t
, а не
int
, но POSIX рекомендует определять
socklen
_t как
uint32_t
.

2. Четыре функции

accept
,
recvfrom
,
getsockname
и
getpeername
передают структуру адреса сокета от ядра к процессу, то есть в направлении, противоположном предыдущему случаю. Этим функциям передается указатель на структуру адреса сокета и указатель на целое число, содержащее размер структуры, как показано в следующем примере:

struct sockaddr_un cli; /*
домен Unix */

socklen_t len;

len = sizeof(cli); /* len - это значение */

getpeername(unixfd, (SA*)&cli, &len);

/* значение len могло измениться */

Причина замены типа для аргумента «длина» с целочисленного на указатель состоит в том, что «длина» эта является и значениемпри вызове функции (сообщает ядру размер структуры, так что ядро при заполнении структуры знает, где нужно остановиться), и результатом, когда функция возвращает значение (сообщает процессу, какой объем информации ядро действительно сохранило в этой структуре). Такой тип аргумента называется аргументом типа «значение-результат»( value-result argument). На рис. 3.3 представлен этот сценарий.

Рис. 3.3. Структура адреса сокета, передаваемая от ядра к процессу

Пример аргументов типа «значение-результат» вы увидите в листинге 4.2.

Если при использовании аргумента типа «значение-результат» для длины структуры структура адреса сокета имеет фиксированную длину (см. рис. 3.1), то значение, возвращаемое ядром, будет всегда равно этому фиксированному размеру: 16 для

sockaddr_in
IPv4 и 24 для
sockaddr_in6
IPv6. Для структуры адреса сокета переменной длины (например,
sockaddr_un
домена Unix) возвращаемое значение может быть меньше максимального размера структуры (вы увидите это в листинге 15.2).

ПРИМЕЧАНИЕ

Мы говорили о структурах адресов сокетов, передаваемых между процессом и ядром. Для такой реализации, как 4.4BSD, где все функции сокетов являются системными вызовами внутри ядра, это верно. Но в некоторых реализациях, особенно в System V, функции сокетов являются лишь библиотечными функциями, которые выполняются как часть обычного пользовательского процесса. То, как эти функции взаимодействуют со стеком протоколов в ядре, относится к деталям реализации, которые обычно нас не волнуют. Тем не менее для простоты изложения мы будем продолжать говорить об этих структурах как о передаваемых между процессом и ядром такими функциями, как bind и connect. (В разделе В.1 вы увидите, что реализации System V действительно передают пользовательские структуры адресов сокетов между процессом и ядром, но как часть сообщений потоков STREAMS.)

Существует еще две функции, передающие структуры адресов сокетов: это recvmsg и sendmsg (см. раздел 14.5). Однако при их вызове поле длины не является отдельным аргументом функции, а передается как одно из полей структуры.

В сетевом программировании наиболее общим примером аргумента типа «значение-результат» может служить длина возвращаемой структуры адреса сокета. Вы встретите и другие аргументы типа «значение-результат»:

Три средних аргумента функции

select
(раздел 6.3).

Аргумент «длина» для функции

getsockopt
(см. раздел 7.2).

Элементы

msg_namelen
и
msg_controllen
структуры
msghdr
при использовании с функцией
recvmsg
(см. раздел 14.5).

Элемент
ifc_len
структуры
ifconf
(см. листинг 17.1).

Первый из двух аргументов длины в функции

sysctl
(см. раздел 18.4).

3.4. Функции определения порядка байтов

Рассмотрим 16-разрядное целое число, состоящее из двух байтов. Возможно два способа хранения этих байтов в памяти. Такое расположение, когда первым идет младший байт, называется прямым порядком байтов( little-endian), а когда первым расположен старший байт — обратным порядком байтов( big-endian). На рис. 3.4 показаны оба варианта.

Рис. 3.4. Прямой и обратный порядок байтов для 16-разрядного целого числа

Сверху на этом рисунке изображены адреса, возрастающие справа налево, а снизу — слева направо. Старший бит( most significant bit, MSB) является в 16-разрядном числе крайним слева, а младший бит( least significant bit, LSB) — крайним справа.

ПРИМЕЧАНИЕ

Термины «прямой порядок байтов» и «обратный порядок байтов» указывают, какой конец многобайтового значения — младший байт или старший — хранится в качестве начального адреса значения.

К сожалению, не существует единого стандарта порядка байтов, и можно встретить системы, использующие оба формата. Способ упорядочивания байтов, используемый в конкретной системе, мы называем порядком байтов узла( host byte order). Программа, представленная в листинге 3.5, выдает порядок байтов узла.

Листинг 3.5. Программа для определения порядка байтов узла

//intro/byteorder.c

1 #include "unp.h"

2 int

3 main(int argc, char **argv)

4 {

5 union {

6 short s;

7 char c[sizeof(short)];

8 } un;

9 un.s = 0x0102;

10 printf("%s: ", CPU_VENDOR_OS);

11 if (sizeof(short) == 2) {

12 if (un.c[0] == 1 && un.c[1] == 2)

13 printf("big-endian\n");

14 else if (un.c[0] == 2 && un.c[1] == 1)

15 printf("little-endian\n");

16 else

17 printf("unknown\n");

18 } else

19 printf('sizeof(short) = %d\n", sizeof(short));

20 exit(0);

21 }

Мы помещаем двухбайтовое значение

0x0102
в переменную типа
short
(короткое целое) и проверяем значения двух байтов этой переменной:
с[0]
(адрес А на рис. 3.4) и
c[1]
(адрес А + 1 на рис. 3.4), чтобы определить порядок байтов.

Поделиться с друзьями: