Scroll to navigation

UNIX(7) Руководство программиста Linux UNIX(7)

ИМЯ

unix - сокеты для локального межпроцессного взаимодействия

ОБЗОР

#include <sys/socket.h>
#include <sys/un.h>

unix_socket = socket(AF_UNIX, type, 0);
error = socketpair(AF_UNIX, type, 0, int *sv);

ОПИСАНИЕ

Семейство сокетов AF_UNIX (также известное, как AF_LOCAL) используется для эффективного взаимодействия между процессами на одной машине. Доменные сокеты UNIX могут быть как безымянными, так и иметь имя файла в файловой системе (типизированный сокет). В Linux также поддерживается абстрактное пространство имён, которое не зависит от файловой системы.

Допустимые типы: потоковый сокет SOCK_STREAM и датаграмный сокет SOCK_DGRAM, сохраняющий границы сообщений (в большинстве реализаций UNIX, доменные датаграмные сокеты UNIX всегда надёжны и не меняют порядок датаграмм); и (начиная с Linux 2.6.4) ориентированный на соединение сокет SOCK_SEQPACKET, сохраняющий границы сообщений и доставляющий сообщения в том же порядке, в каком они были отправлены.

Доменные сокеты UNIX поддерживают передачу файловых дескрипторов или информацию (credentials) о процессе другим процессам, используя вспомогательные (ancillary) данные.

Формат адреса

Адрес доменного сокета UNIX представляет собой следующую структуру:

#define UNIX_PATH_MAX    108
struct sockaddr_un {

sa_family_t sun_family; /* AF_UNIX */
char sun_path[UNIX_PATH_MAX]; /* имя пути */ };

sun_family всегда содержит AF_UNIX.

В этой структуре различают три типа адресов:

  • с именем пути: доменный сокет UNIX может быть привязан к имени пути (с завершающимся null) в файловой системе с помощью bind(2). При возврате адреса сокета с помощью getsockname(2), getpeername(2) и accept(2), его длина равна offsetof(struct sockaddr_un, sun_path) + strlen(sun_path) + 1, а в sun_path содержится имя пути с завершающимся null.
  • безымянный: Потоковый сокет, который не привязан к имени пути с помощью bind(2), не имеет имени. Аналогично, два сокета, создаваемые socketpair(2), также не имеют имён. При возврате адреса сокета с помощью getsockname(2), getpeername(2) и accept(2), его длина равна sizeof(sa_family_t), а значение sun_path не используется.
  • абстрактный: абстрактный адрес сокета отличается тем, что значением sun_path[0] является байт null ('\0'). Адрес сокета в этом пространстве имён определяется дополнительными байтами в sun_path, количество которых определяется длиной указанной структуры адреса. Байты null в имени не имеют специального значения. Имя не связано с именем пути в файловой системе. При возврате адреса абстрактного сокета с помощью getsockname(2), getpeername(2) и accept(2), возвращаемое значение addrlen больше чем sizeof(sa_family_t) (т.е. больше 2), а имя сокета содержится в первых (addrlen - sizeof(sa_family_t)) байтах sun_path. Пространство имён абстрактных сокетов является непереносимым расширением Linux.

Параметры сокетов

В силу исторических причин эти параметры сокетов относятся к типу SOL_SOCKET, даже если они относятся к AF_UNIX. Они могут быть установлены с помощью setsockopt(2) и прочитаны с помощью getsockopt(2); тип SOL_SOCKET указывается в качестве семейства сокета.

Разрешает приём информационных данных (credentials) посылающего процесса во вспомогательном сообщении. Если при включении этого параметра сокет пока ещё не соединён, то в абстрактном пространстве имён будет автоматически создано уникальное имя. Ожидается целочисленный логический флаг.

Свойство автоматической привязки

Если в вызов bind(2) передано значение addrlen равное sizeof(sa_family_t), или для сокета, который не привязан к адресу явно, был указан параметр сокета SO_PASSCRED, то сокет автоматически привязывается к абстрактному адресу. Адрес состоит из байта null и 5 байтов символов из набора [0-9a-f]. Таким образом, максимальное количество автоматически привязываемых адресов равно 2^20 (в Linux 2.1.15, когда была добавлена автоматическая привязка, использовалось 8 байт, и, таким образом, ограничение было 2^32 адресов. В Linux 2.3.15 количество байт сократили до 5).

Программный интерфейс сокетов

В следующих параграфах описываются специфичные тонкости доменов и неподдерживаемые возможности программного интерфейса сокетов для доменных сокетов UNIX в Linux.

Доменные сокеты UNIX не поддерживают передачу внеполосных данных (флаг MSG_OOB у send(2) и recv(2)).

Флаг MSG_MORE у send(2) не поддерживается доменными сокетами UNIX.

Использование MSG_TRUNC в аргументе flags у recv(2) не поддерживается доменными сокетами UNIX.

Параметр сокета SO_SNDBUF учитывается в доменных сокетах UNIX, а параметр SO_RCVBUF — нет. Для датаграмных сокетов значение SO_SNDBUF считается максимальным размером для исходящих датаграмм. Это ограничение, вычисляемое как удвоенное значение (см. socket(7)) параметра, содержит меньше 32 байт накладных расходов.

Вспомогательные сообщения

Вспомогательные данные отправляются и принимаются с помощью sendmsg(2) и recvmsg(2). В силу исторических причин перечисленные типы вспомогательных сообщений относятся к типу SOL_SOCKET, даже если они относятся к AF_UNIX. Для того, чтобы отправить их, установите значение поля cmsg_level структуры cmsghdr равным SOL_SOCKET, а в значении поля cmsg_type укажите его тип. Дополнительная информация приведена в cmsg(3).

Передать или принять набор открытых файловых дескрипторов из другого процесса. Часть с данными содержит целочисленный массив файловых дескрипторов. Переданные файловые дескрипторы действуют так, как если бы они были созданы dup(2).
Передать или принять информацию о UNIX. Может быть использовано для аутентификации. Информация передаётся в виде структуры struct ucred вспомогательного сообщения. Эта структура определена в <sys/socket.h> следующим образом:


struct ucred {

pid_t pid; /* идентификатор посылающего процеса */
uid_t uid; /* идентификатор пользователя посылающего процесса */
gid_t gid; /* идентификатор группы посылающего процесса */ };

Начиная с glibc 2.8, чтобы получить определение данной структуры должен быть определён макрос тестирования свойств _GNU_SOURCE (до включения каких-либо заголовочных файлов).

Информация (credentials), указываемая отправителем, проверяется ядром. Процесс с идентификатором эффективного пользователя 0 может указывать значения, отличные от его собственных. Отправитель должен указать идентификатор своего процесса (если только он не имеет мандата CAP_SYS_ADMIN), свой идентификатор пользователя, эффективный идентификатор или сохранённый set-user-ID (если только он не имеет CAP_SETUID) и идентификатор своей группы, эффективный идентификатор группы или сохранённый set-group-ID (если только он не имеет CAP_SETGID). Для получения сообщения со структурой struct ucred для сокета нужно включить параметр SO_PASSCRED.

Вызовы ioctl

Следующие вызовы ioctl(2) возвращают информацию в аргументе value. Корректный синтаксис:

int value;
error = ioctl(unix_socket, ioctl_type, &value);

Значением ioctl_type может быть:

Возвращает количество непрочитанных данных в очереди в приёмном буфере. Сокет не должен быть в состоянии LISTEN, иначе возвращается ошибка (EINVAL). Значение SIOCINQ определено в <linux/sockios.h>. В качестве альтернативы вы можете использовать синоним FIONREAD, определённый в <sys/ioctl.h>.

ОШИБКИ

Заданный локальный адрес уже используется, или сокетный объект файловой системы уже существует.
Удалённый адрес, указанный connect(2) не является слушающим сокетом. Эта ошибка также может возникнуть, если имя файла назначения не является сокетом.
Удалённый сокет был неожиданно закрыт.
Некорректный адрес пользовательской памяти.
Передан неправильный аргумент. Основная причина — не задано значение AF_UNIX в поле sun_type передаваемых адресов или сокет находится в некорректном состоянии для производимой операции.
Вызов connect(2) запущен для уже соединённого сокета, или адрес назначения указывает на соединённый сокет.
Путь, указанный в удалённом адресе для connect(2), не существует.
Не хватает памяти.
Для операции над сокетом требуется адрес назначения, а сокет не соединён.
Вызвана потоковая операция для непотокового сокета, или произведена попытка использования параметра для внеполосных данных.
Отправитель указал неправильную информацию (credentials) в структуре struct ucred.
Удалённый сокет был закрыт в потоковом сокете. Если разрешено, также будет послан сигнал SIGPIPE. Этого можно избежать, передав флаг MSG_NOSIGNAL при вызове sendmsg(2) или recvmsg(2).
Указанный протокол не является AF_UNIX.
Удалённый сокет не совпадает с типом локального сокета (SOCK_DGRAM против SOCK_STREAM).
Неизвестный тип сокета.

При создании сокетного объекта на уровне сокетов или файловой системы могут генерироваться другие ошибки. За дополнительной информацией обращайтесь к соответствующей справочной странице.

ВЕРСИИ

SCM_CREDENTIALS и абстрактное пространство имён появились в Linux 2.2 и не должны использоваться в переносимых программах. Некоторые клоны BSD также поддерживают передачу дополнительной информации (credential), но методы реализации передачи могут серьезно отличаться на разных системах.

ЗАМЕЧАНИЯ

В реализации Linux учитываются права доступа к каталогу, в котором находятся сокеты, видимые в файловой системе. Владелец, группа и права, присвоенные сокетам, могут быть изменены. Если процесс не имеет прав на запись и поиск (запуск) в каталоге, то создать новый сокет в нём не удастся. Соединение сокетных объектов требует права на запись/чтение. Это действие отличается от действий большинства клонов BSD, игнорирующих права доменных сокетов UNIX. Переносимые программы не должны полагаться на эту возможность для обеспечения безопасности.

Привязка сокета к имени файла создаёт сокет в файловой системе, который должен быть удалён создателем, когда необходимость в нём отпадёт (с помощью unlink(2)). Обычная система ссылок UNIX также подходит для работы с сокетами; сокет может быть удалён в любое время, а реальное удаление из файловой системы будет произведено при закрытии последней на него ссылки.

Для передачи файловых дескрипторов или информации (credentials) через SOCK_STREAM необходимо передать/принять, по меньшей мере, один байт недополнительных данных в одном из вызовов: sendmsg(2) или recvmsg(2).

В потоковых доменных сокетах UNIX отсутствует такое понятие как внеполосные данные.

ПРИМЕР

См. bind(2).

Пример использования SCM_RIGHTS приведён в cmsg(3).

СМОТРИТЕ ТАКЖЕ

recvmsg(2), sendmsg(2), socket(2), socketpair(2), cmsg(3), capabilities(7), credentials(7), socket(7)

2012-05-10 Linux