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

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

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

Этот флаг введен в Net/3 и может не поддерживаться в некоторых системах.

■ MSG_OOB. С функцией send этот флаг указывает, что отправляются внеполосные данные. В случае TCP в качестве внеполосных данных должен быть отправлен только 1 байт, как показано в главе 21. С функцией recv этот флаг указывает на то, что вместо обычных данных должны читаться внеполосные данные.

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

■ MSG_WAITALL. Этот флаг был впервые введен в 4.3BSD Reno. Он сообщает ядру, что операция чтения должна выполняться до тех пор, пока не будет прочитано запрашиваемое количество байтов. Если система поддерживает этот флаг, мы можем опустить функцию readn (см. листинг 3.9) и заменить ее макроопределением

#define readn(fd, ptr, n) recv(fd, ptr, n, MSG_WAITALL)

Даже если мы задаем флаг MSG_WAITALL, функция может возвратить количество байтов меньше запрашиваемого в том случае, если или перехватывается сигнал, или соединение завершается, или есть ошибка сокета, требующая обработки.

Существуют дополнительные флаги, используемые протоколами, отличными от TCP/IP. Например, транспортный уровень OSI основан на записях (а не на потоке байтов, как TCP), и для операций вывода поддерживает флаг MSG_EOR, задающий конец логической записи.

С аргументом flags связана одна фундаментальная проблема: он передается по значению и не является аргументом типа «значение-результат». Следовательно, он может использоваться только для передачи флагов от процесса к ядру. Ядро не может передать флаги обратно процессу. Это не представляет проблемы с TCP/IP, поскольку очень редко бывает необходимо передавать флаги обратно процессу от ядра. Но когда к 4.3BSD Reno были добавлены протоколы OSI, появилась необходимость возвращать процессу флаг MSG_EOR при операции ввода. В 4.3BSD Reno было принято решение оставить аргументы для общеупотребительных функций (recv и recvfrom) как есть и изменить структуру msghdr, которая используется с функциями recvmsg и sendmsg. В разделе 14.5 мы увидим, что в эту структуру был добавлен целочисленный элемент msg_flags, и поскольку структура передается по ссылке, ядро может изменить флаги, содержащиеся в этом элементе, по завершении функции. Это значит также, что если процессу необходимо, чтобы флаги изменялись ядром, процесс должен вызвать функцию recvmsg вместо вызова функции recv или recvfrom.

14.4. Функции readv и writev

Эти две функции аналогичны функциям read и write, но readv и writev позволяют использовать для чтения или записи один или более буферов с помощью одного вызова функции. Эти операции называются операциями распределяющего чтения (scatter read) (поскольку вводимые данные распределяются по нескольким буферам приложения) и объединяющей записи (gather write) (поскольку данные из нескольких буферов объединяется для одной операции вывода).

#include <sys/uio.h>


ssize_t readv(int filedes, const struct iovec *iov, int iovcnt);

ssize_t writev(int filedes, const struct iovec *iov, int iovcnt);

Обе функции возвращают: количество считанных или записанных байтов, -1 в случае ошибки

Второй аргумент обеих функций — это указатель на массив структур iovec, для определения которого требуется включить заголовочный файл <sys/uio.h>:

struct iovec {

 void *iov_base; /* начальный адрес буфера */

 size_t iov_len; /* размер буфера */

};

ПРИМЕЧАНИЕ

Типы данных элементов структуры iovec определяются POSIX. Вам могут встретиться реализации, определяющие iov_base как char*, a iov_len как int.

Существует некоторый предел числа элементов в массиве структур iovec, зависящий от реализации. Linux позволяет использовать до 1024 элементов, а HP-UD — до 2100. POSIX требует, чтобы константа IOV_MAX определялась включением заголовочного файла <sys/uio.h> и чтобы ее значение было не менее 16.

Функции readv и writev могут использоваться с любым дескриптором, а не только с сокетами. Кроме того, writev является атомарной операцией. Для протокола, основанного на записях, такого как UDP, один вызов функции writev генерирует одну дейтаграмму UDP.

Мы отметили одно использование функции writev с параметром сокета TCP_NODELAY в разделе 7.9. Мы сказали, что при записи с помощью функции write 4 байт и затем 396 байт может активизироваться алгоритм Нагла, и предпочтительное решение в данном случае заключается в вызове функции writev для двух буферов.

14.5. Функции recvmsg и sendmsg

Эти две функции являются наиболее общими для всех операций ввода-вывода. Действительно, мы можем заменить все вызовы функций ввода read, readv, recv и recvfrom вызовами функции recvmsg. Аналогично, все вызовы различных функций вывода можно заменить вызовами функции sendmsg.

#include <sys/socket.h>


ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

ssize_t sendmsg(int sockfd, struct msghdr *msg, int flags);

Обе функции возвращают: количество прочитанных или записанных байтов в случае успешного выполнения, -1 в случае ошибки

Большинство аргументов обеих функций скрыто в структуре msghdr:

struct msghdr {

 void         *msg_name;     /* адрес протокола */

 socklen_t    msg_namelen;   /* размер адреса протокола */

 struct iovec *msg_iov;      /* массив буферов */

 size_t       msg_iovlen;    /* количество элементов в массиве msg_iov */

 void         *msg_control;  /* вспомогательные данные: должны быть

                                выровнены для структуры cmsghdr */

 socklen_t    msg_controllen; /* размер вспомогательных данных */

 int          msg_flags;      /* флаги, возвращенные функцией recvmsg() */

};

ПРИМЕЧАНИЕ

Показанная нами структура msghdr восходит к 4.3BSD Reno и определяется POSIX. Некоторые системы (например, Solaris 2.5) используют более раннюю структуру msghdr, которая появилась в 4.2BSD. У более ранней структуры нет элемента msg_flags, а элементы msg_control и msg_controllen называются msg_accrights и msg_accrightslen. В этой системе поддерживается только одна форма вспомогательных данных — передача дескрипторов файлов (так называемые права доступа). При появлении протоколов OSI в 4.3BSD Reno были добавлены новые формы вспомогательных данных, вследствие чего были обобщены имена элементов структуры.

Элементы msg_name и msg_namelen используются, когда сокет не является присоединенным (например, неприсоединенный сокет UDP). Они аналогичны пятому и шестому аргументам функций recvfrom и sendto: msg_name указывает на структуру адреса сокета, в которой вызывающий процесс хранит адрес протокола получателя для функции sendmsg или функция recvmsg хранит адрес протокола отправителя. Если нет необходимости задавать адрес протокола (например, сокет TCP или присоединенный сокет UDP), элемент msg_name должен быть пустым указателем. Элемент msg_namelen является аргументом типа «значение» для функции sendmsg, но для функции recvmsg это аргумент типа «значение-результат».

Элементы msg_iov и msg_iovlen задают массив буферов ввода и вывода (массив структур iovec), аналогичный второму и третьему аргументам функций readv и writev.

Элементы msg_control и msg_controllen задают расположение и размер необязательных вспомогательных данных. Элемент msg_controllen — это аргумент типа «значение-результат» функции recvmsg. Вспомогательные данные мы рассматриваем в разделе 14.6.

Работая с функциями recvmsg и sendmsg, следует учитывать различие между двумя флаговыми переменными: это аргумент flags, который передается по значению, и элемент msg_flags структуры msghdr, который передается по ссылке (поскольку функции передается адрес этой структуры).

■ Элемент msg_flags используется только функцией recvmsg. Когда вызывается функция recvmsg, аргумент flags копируется в элемент msg_flags [128, с. 502], и это значение используется ядром для управления приемом данных. Затем это значение обновляется в зависимости от результата функции recvmsg.

■ Элемент msg_flags игнорируется функцией sendmsg, поскольку эта функция использует аргумент flags для управления выводом данных. Это значит, что если мы хотим установить флаг MSG_DONTWAIT при вызове функции sendmsg, то мы должны присвоить это значение аргументу flags, а присваивание значения MSG_DONTWAIT элементу msg_flags не имеет никакого эффекта.

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