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

Глава 15

Доменные протоколы Unix

15.1. Введение

Доменные протоколы Unix — это не набор протоколов, а способ связи клиентов и серверов на отдельном узле, использующий тот же API, который используется для клиентов и серверов на различных узлах, — сокеты или XTI. Доменные протоколы Unix представляют альтернативу методам IPC (Interprocess Communications — взаимодействие процессов), которым посвящен второй том[2] этой серии, применяемым, когда клиент и сервер находятся на одном узле. Подробности действительной реализации доменных сокетов Unix в ядре, происходящем от Беркли, приводятся в третьей части [112].

В домене Unix предоставляются два типа сокетов: потоковые (аналогичные сокетам TCP) и дейтаграммные (аналогичные сокетам UDP). Хотя предоставляется также и символьный сокет, но его семантика никогда не документировалась, он не используется никакой из известных автору программ и не определяется в POSIX.

Доменные сокеты Unix используются по трем причинам.

1. В реализациях, происходящих от Беркли, доменные сокеты Unix часто вдвое быстрее сокетов TCP, когда оба собеседника находятся на одном и том же узле [112, с. 223–224]. Есть приложение, которое использует это преимущество: X Window System. Когда клиент X11 запускается и открывает соединение с сервером X11, клиент проверяет значение переменной окружения DISPLAY, которая задает имя узла сервера, окно и экран. Если сервер находится на том же узле, что и клиент, клиент открывает потоковое соединение с сервером через доменный сокет Unix, в противном случае клиент открывает соединение TCP.

2. Доменные сокеты Unix используются при передаче дескрипторов между процессами на одном и том же узле. Пример мы приводим в разделе 15.7.

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

Адреса протоколов, используемые для идентификации клиентов и серверов в домене Unix, — это полные имена в обычной файловой системе. Вспомните, что IPv4 использует комбинацию 32-разрядных адресов и 16-разрядных номеров портов для своих адресов протоколов, а IPv6 для своих адресов протоколов использует комбинацию 128-разрядных адресов и 16-разрядных номеров портов. Эти полные имена не являются обычными именами файлов Unix: в общем случае мы не можем читать из этих файлов или записывать в них. Это может делать только программа, связывающая полное имя с доменным сокетом Unix.

15.2. Структура адреса доменного сокета Unix

В листинге 15.1[1] показана структура адреса доменного сокета Unix, задаваемая включением заголовочного файла

<sys/un.h>
.

Листинг 15.1. Структура адреса доменного сокета Unix: sockaddr_un

struct sockaddr_un {

 uint8_t     sun_len;

 sa_family_t sun_family;    /* AF_LOCAL */

 char        sun_path[104]; /* полное имя, оканчивающееся нулем */

};

ПРИМЕЧАНИЕ

POSIX не задает длину массива sun_path и предупреждает, что разработчику приложения не следует делать предположений об этой длине. Воспользуйтесь оператором sizeof для определения длины массива во время выполнения программы. Убедитесь, что полное имя помещается в этот массив. Длина, скорее всего, будет где-то между 92 и 108. Причина этих ограничений — в артефакте реализации, возникшем еще в 4.2BSD, где требовалось, чтобы структура помещалась в 128-байтовый буфер памяти ядра mbuf.

Полное имя, хранимое в символьном массиве

sun_path
, должно завершаться нулем. Имеется макрос
SUN_LEN
, который получает указатель на структуру
sockaddr_un
и возвращает длину структуры, включая число непустых байтов в полном имени. Неопределенный адрес обозначается пустой строкой, то есть элемент
sun_path[0]
должен быть равен нулю. Это эквивалент константы
INADDR_ANY
протокола IPv4 и константы
IN6ADDR_ANY_INIT
протокола IPv6 для домена Unix.

ПРИМЕЧАНИЕ

В POSIX доменным протоколам Unix дали название «локального IPC», чтобы не подчеркивать зависимость от операционной системы Unix. Историческая константа AF_UNIX становится константой AF_LOCAL. Тем не менее мы будем продолжать использовать термин «домен Unix», так как он стал именем де-факто, независимо от соответствующей операционной системы. Кроме того, несмотря на попытку POSIX исключить зависимость от операционной системы, структура адреса сокета сохраняет суффикс _un!

Пример: функция bind и доменный сокет Unix

Программа, показанная в листинге 15.2, создает доменный сокет Unix, с помощью функции

bind
связывает с ним полное имя и затем вызывает функцию
getsockname
и выводит это полное имя.

Листинг 15.2. Связывание полного имени с доменным сокетом Unix

unixdomain/unixbind.c

 1 #include "unp.h"

 2 int

 3 main(int argc, char **argv)

 4 {

 5  int sockfd;

 6  socklen_t len;

 7  struct sockaddr_un addr1, addr2;

 8  if (argc != 2)

 9   err_quit("usage: unixbind <pathname>");

10  sockfd = Socket(AF_LOCAL, SOCK_STREAM, 0);

11  unlink(argv[1]); /* игнорируем возможную ошибку */

12  bzero(&addr1, sizeof(addr1));

13  addr1.sun_family = AF_LOCAL;

14  strncpy(addr1.sun_path, argv[1], sizeof(addr1.sun_path) - 1);

15  Bind(sockfd, (SA*)&addr1, SUN_LEN(&addr1));

16  len = sizeof(addr2);

17  Getsockname(sockfd, (SA*)&addr2, &len);

18  printf("bound name = %s, returned len = %d\n", addr2.sun_path, len);

19  exit(0);

20 }

Удаление файла

11
 Полное имя, которое функция
bind
должна связать с сокетом, — это аргумент командной строки. Если это полное имя уже существует в файловой системе, при выполнении функции
bind
возникает ошибка. Следовательно, мы вызываем функцию
unlink
, чтобы удалить файл в том случае, если он уже существует. Если его не существует, функция
unlink
возвращает ошибку, которую мы игнорируем.

вернуться

2

Стивенс У. UNIX: взаимодействие процессов. — СПб.: Питер, 2002.

вернуться

1

Все исходные коды программ, опубликованные в этой книге, вы можете найти по адресу http://www.piter.com.

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