чтобы облегчить этот процесс, вводится системный вызов socketpair().

#include <sys/socket.h>

int socketpair(int domain, int type, int protocol, int sockfds[2]);

Первые три параметра совпадают с теми, которые передаются в socket(). Последний параметр sockfds() заполняется функцией socketpair() двумя файловыми дескрипторами (по одному для каждой стороны сокета).

Пример применения socketpair() показан далее в главе.

17.4.6. Передача файловых дескрипторов

Сокеты домена Unix обладают уникальным свойством: через них могут передаваться файловые дескрипторы. Ни один из прочих механизмов IPC не поддерживает подобную возможность. Она позволяет процессу открыть файл и передать файловый дескриптор в другой (возможно, несвязанный) процесс. Все проверки доступа выполняются при открытии файла, поэтому получающий процесс приобретает те же самые права доступа к файлу, что и исходный процесс.

Файловые дескрипторы передаются как часть более сложного сообщения, которое отправляется с помощью системного вызова sendmsg() и принимается через recvmsg().

#include <sys/socket.h>

int sendmsg(int fd, const struct msghdr * msg, unsigned int flags);

int recvmsg(int fd, struct msghdr * msg, unsigned int flags);

Параметр fd является файловым дескриптором, через который передается сообщение; второй параметр служит указателем на структуру, описывающую сообщение. Параметр flags обычно не используется и для большинства приложений должен быть равен нулю. В специализированных книгах по программированию для сетей обсуждаются доступные флаги [33].

Сообщение описывается показанной ниже структурой.

#include <sys/socket.h>

#include <sys/un.h>

struct msghdr {

 void * msg_name;            /* дополнительный адрес */

 unsigned int msg_namelen;   /* размер msg_name */

 struct iovec * msg_iov;     /* массив для чтения вразброс/сборной записи*/

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

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

 unsigned int msg_controllen;/* длина буфера вспомогательных данных */

 int msg_flags;              /* флаги на получаемом сообщении */

};

Первые два члена msg_name и msg_namelen не используются в потоковых протоколах. Приложения, посылающие сообщения через потоковые сокеты, должны устанавливать для msg_name значение NULL, для msg_namelen — ноль.

msg_iov и msg_iovlen описывают набор буферов, которые отправляют или принимают. Чтение вразброс и сборная запись, а также struct iovec, обсуждаются в конце главы 13. Последний член структуры msg_flags в настоящее время не используется и должен равняться нулю.

Два элемента, которые мы пропустили, msg_control и msg_controllen предоставляют возможность передачи файлового дескриптора. Член msg_control указывает на массив заголовков управляющих сообщений; msg_controllen устанавливает количество байт, которые содержит массив. Каждое управляющее сообщение состоит из структуры struct cmsghdr, которая сопровождается дополнительными данными.

#include <sys/socket.h>

struct cmsghdr {

 unsigned int cmsg_len; /* длина управляющего сообщения */

 int cmsg_level;        /* SOL_SOCKET */

 int cmsg_type;         /* SCM_RIGHTS */

 int cmsg_data[0];      /* здесь должен быть файловый дескриптор */

};

Размер управляющего сообщения, включая заголовок, хранится в переменной cmsg_len. В текущий момент определен только один тип управляющих сообщений — SCM_RIGHTS, который передает файловые дескрипторы [125]. Для данного типа сообщений параметры cmsg_level и cmsg_type должны быть равны соответственно SOL_SOCKET и SCM_RIGHTS. Последний член cmsg_data является массивом нулевого размера. Это расширение gcc, которое позволяет приложению копировать данные в конец структуры (в следующей программе показан пример).

Получение файлового дескриптора происходит аналогично. Необходимо выделить достаточное пространство буфера для управляющего сообщения, и каждая приходящая структура struct cmsghdr будет сопровождаться новым файловым дескриптором.

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

  1: /* passfd.с */

  2:

  3: /* Программа ведет себя подобно обычной команде /bin/cat, которая обрабатывает

  4:    только один аргумент (имя файла). Мы создаем сокеты домена Unix при помощи

  5:    socketpair(), затем разветвляем через fork(). Дочерний процесс открывает файл,

  6:    имя которого передается в командной строке, пересылает файловый дескриптор и

  7:    имя файла обратно в порождающий процесс, после этого завершается. Родительский

  8:    процесс ожидает файловый дескриптор от дочернего процесса, а потом копирует

  9:    данные из файлового дескриптора в stdout до тех пор, пока данные не

 10:    заканчиваются. Затем родительский процесс завершается. */

 11:

 12: #include <alloca.h>

 13: #include <fcntl.h>

 14: #include <stdio.h>

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату