Литмир - Электронная Библиотека
Содержание  
A
A

unsigned char *CMSG_DATA(struct cmsghdr *<i>cmsgptr</i>);

<i>Возвращает: указатель на первый байт данных, связанных со структурой cmsghdr</i>

unsigned int CMSG_LEN(unsigned int <i>length</i>);

<i>Возвращает: значение, которое записывается в cmsg_len</i>

unsigned int CMSG_SPACE(unsigned int <i>length</i>);

<i>Возвращает: общий размер объекта вспомогательных данных</i>

ПРИМЕЧАНИЕ

В POSIX определены первые пять макросов, а в [113] определены последние два.

Эти макросы могли бы быть использованы в следующем псевдокоде:

struct msghdr msg;

struct cmsghdr *cmsgptr;

/* заполнение структуры msg */

/* вызов recvmsg() */

for (cmsgptr = CMSG_FIRSTHDR(&amp;msg); cmsgptr != NULL;

 cmsgptr = CMSG_NXTHDR(&amp;msg, cmsgptr)) {

 if (cmsgptr-&gt;cmsg_level == ... &amp;&amp;

  cmsgptr-&gt;cmsg_type == ...) {

  u_char *ptr;

  ptr = CMSG_DATA(cmsgptr);

  /* обработка данных, на которые указывает ptr */

 }

}

Макрос

CMSG_FIRSTHDR
возвращает указатель на первый объект вспомогательных данных или пустой указатель, если в структуре
msghdr
нет вспомогательных данных (или
msg_control
является пустым указателем, или
cmsg_len
меньше размера структуры
cmsghdr
). Макрос
CMSG_NXTHDR
возвращает пустой указатель, когда в буфере управления нет другого объекта вспомогательных данных.

ПРИМЕЧАНИЕ

Многие существующие реализации макроса CMSG_FIRSTHRD никогда не используют элемент msg_controllen и просто возвращают значение cmsg_control. В листинге 22.2 мы проверяем значение msg_controllen перед вызовом макроопределения.

Разница между макросами

CMSG_LEN
и
CMSG_SPACE
заключается в том, что первый возвращает длину объекта вместе с дополняющими нулями (это значение хранится в
cmsg_len
), а последний возвращает длину собственно объекта (это значение может использоваться для динамического выделения памяти под объект).

14.7. Сколько данных находится в очереди?

Иногда требуется узнать, сколько данных находится в очереди для чтения данного сокета, не считывая эти данные. Для этого имеется три способа.

1. Если нашей целью не является блокирование в ядре (поскольку мы можем выполнять другие задачи, пока данные для чтения еще не готовы), может использоваться неблокируемый ввод-вывод. Мы обсуждаем его в главе 16.

2. Если мы хотим проверить данные, но при этом оставить их в приемном буфере для считывания какой-либо другой частью процесса, мы можем использовать флаг

MSG_PEEK
(см. табл. 14.1). Если мы не уверены, что какие-либо данные готовы для чтения, мы можем объединить этот флаг с отключением блокировки для сокета или с флагом
MSG_DONTWAIT
.

Помните о том, что для потокового сокета количество данных в приемном буфере может изменяться между двумя последовательными вызовами функции

recv
. Например, предположим, что мы вызываем recv для сокета TCP, задавая буфер длиной 1024 и флаг
MSG_PEEK
, и возвращаемое значение равно 100. Если затем мы снова вызовем функцию recv, возможно, возвратится более 100 байт (мы задаем длину буфера больше 100), поскольку в промежутке между двумя нашими вызовами
recv
могли быть получены дополнительные данные.

А что произойдет в случае сокета UDP, когда в приемном буфере имеется дейтаграмма? При вызове

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

3. Некоторые реализации поддерживают команду

FIONREAD
функции
ioctl
. Третий аргумент функции
ioctl
— это указатель на целое число, а возвращаемое в этом целом числе значение — это текущее число байтов в приемном буфере сокета [128, с. 553]. Это значение является общим числом установленных в очередь байтов, которое для сокета UDP включает все дейтаграммы, установленные в очередь. Также помните о том, что значение, возвращаемое для сокета UDP, в Беркли-реализациях включает пространство, требуемое для структуры адреса сокета, содержащей IP-адрес отправителя и порт для каждой дейтаграммы (16 байт для IP4, 24 байта для IP6).

14.8. Сокеты и стандартный ввод-вывод

Во всех наших примерах мы применяли то, что иногда называется вводом-выводом Unix, вызывали функции

read
и
write
и их разновидности (
recv
,
send
и т.д.). Эти функции работают с дескрипторами и обычно реализуются как системные вызовы внутри ядра Unix.

Другой метод выполнения ввода-вывода заключается в использовании стандартной библиотеки ввода-вывода. Она задается стандартом ANSI С и была задумана как библиотека, совместимая с не-Unix системами, поддерживающими ANSI С. Стандартная библиотека ввода-вывода обрабатывает некоторые моменты, о которых мы должны заботиться сами при использовании функций ввода- вывода Unix, таких как автоматическая буферизация потоков ввода и вывода. К сожалению, ее обработка буферизации потока может представить новый ряд проблем, о которых следует помнить. Глава 5 [110] подробно описывает стандартную библиотеку ввода-вывода, а в [92] представлена полная реализация стандартной библиотеки ввода-вывода и ее обсуждение.

ПРИМЕЧАНИЕ

При обсуждении стандартной библиотеки ввода-вывода используется термин «поток» в выражениях типа «мы открываем поток ввода» или «мы очищаем поток вывода». Не путайте это с подсистемой потоков STREAMS, которую мы обсуждаем в главе 31.

161
{"b":"225366","o":1}