UNIX: разработка сетевых приложений
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(&msg); cmsgptr != NULL;cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {if (cmsgptr->cmsg_level == ... &&cmsgptr->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_len14.7. Сколько данных находится в очереди?
Иногда требуется узнать, сколько данных находится в очереди для чтения данного сокета, не считывая эти данные. Для этого имеется три способа.
1. Если нашей целью не является блокирование в ядре (поскольку мы можем выполнять другие задачи, пока данные для чтения еще не готовы), может использоваться неблокируемый ввод-вывод. Мы обсуждаем его в главе 16.
2. Если мы хотим проверить данные, но при этом оставить их в приемном буфере для считывания какой-либо другой частью процесса, мы можем использовать флаг
(см. табл. 14.1). Если мы не уверены, что какие-либо данные готовы для чтения, мы можем объединить этот флаг с отключением блокировки для сокета или с флагомMSG_PEEK.MSG_DONTWAITПомните о том, что для потокового сокета количество данных в приемном буфере может изменяться между двумя последовательными вызовами функции
. Например, предположим, что мы вызываем recv для сокета TCP, задавая буфер длиной 1024 и флагrecv, и возвращаемое значение равно 100. Если затем мы снова вызовем функцию recv, возможно, возвратится более 100 байт (мы задаем длину буфера больше 100), поскольку в промежутке между двумя нашими вызовамиMSG_PEEKмогли быть получены дополнительные данные.recvА что произойдет в случае сокета UDP, когда в приемном буфере имеется дейтаграмма? При вызове
с флагомrecvfrom, за которым последует другой вызов без заданияMSG_PEEK, возвращаемые значения обоих вызовов (размер дейтаграммы, ее содержимое и адрес отправителя) будут совпадать, даже если в приемный буфер сокета между двумя вызовами добавляются дополнительные дейтаграммы. (Мы считаем, конечно, что никакой другой процесс не использует тот же дескриптор и не осуществляет чтение из данного сокета в это же время.)MSG_PEEK3. Некоторые реализации поддерживают команду
функцииFIONREAD. Третий аргумент функцииioctl— это указатель на целое число, а возвращаемое в этом целом числе значение — это текущее число байтов в приемном буфере сокета [128, с. 553]. Это значение является общим числом установленных в очередь байтов, которое для сокета UDP включает все дейтаграммы, установленные в очередь. Также помните о том, что значение, возвращаемое для сокета UDP, в Беркли-реализациях включает пространство, требуемое для структуры адреса сокета, содержащей IP-адрес отправителя и порт для каждой дейтаграммы (16 байт для IP4, 24 байта для IP6).ioctl14.8. Сокеты и стандартный ввод-вывод
Во всех наших примерах мы применяли то, что иногда называется вводом-выводом Unix, вызывали функции
иreadи их разновидности (write,recvи т.д.). Эти функции работают с дескрипторами и обычно реализуются как системные вызовы внутри ядра Unix.sendДругой метод выполнения ввода-вывода заключается в использовании стандартной библиотеки ввода-вывода. Она задается стандартом ANSI С и была задумана как библиотека, совместимая с не-Unix системами, поддерживающими ANSI С. Стандартная библиотека ввода-вывода обрабатывает некоторые моменты, о которых мы должны заботиться сами при использовании функций ввода- вывода Unix, таких как автоматическая буферизация потоков ввода и вывода. К сожалению, ее обработка буферизации потока может представить новый ряд проблем, о которых следует помнить. Глава 5 [110] подробно описывает стандартную библиотеку ввода-вывода, а в [92] представлена полная реализация стандартной библиотеки ввода-вывода и ее обсуждение.
ПРИМЕЧАНИЕПри обсуждении стандартной библиотеки ввода-вывода используется термин «поток» в выражениях типа «мы открываем поток ввода» или «мы очищаем поток вывода». Не путайте это с подсистемой потоков STREAMS, которую мы обсуждаем в главе 31.