Одно из отличий вызова socketpair() от выполнения аналогичной операции вручную заключается в том, что сокеты не привязываются ни к какому адресу. Это позволяет избежать целого ряда уязвимостей в безопасности, поскольку другие процессы таких сокетов не видят.

53.6. Абстрактное пространство имен сокетов в Linux

Так называемое абстрактное пространство имен является одной из уникальных возможностей Linux, которая позволяет привязывать сокет домена UNIX к имени, не имеющему отношения к файловой системе. Это дает несколько потенциальных преимуществ:

• можно не беспокоиться о возможных конфликтах с существующими файлами;

• после завершения работы с сокетом не нужно удалять соответствующий файл. Абстрактное имя автоматически исчезает вместе с закрытием сокета;

• нет нужды создавать для сокета отдельный файл. Это может пригодиться в среде chroot или при отсутствии прав на запись в файловую систему.

Чтобы создать абстрактную привязку, нужно сделать первый байт поля sun_path нулевым (\0). Это отличает абстрактные имена сокетов от традиционных, принятых в домене UNIX и состоящих из одного или несколько ненулевых байтов, в конце которых находится нулевой символ. Остальные байты поля sun_path определяют абстрактное имя сокета. Данное имя не предусматривает завершающего символа, поэтому учитывается каждый байт.

Создание абстрактной привязки для сокета демонстрируется в листинге 53.8.

Листинг 53.8. Создание абстрактной привязки для сокета

Из файла sockets/us_abstract_bind.c

#include

#include

#include "tlpi_hdr.h"

int

main(int argc, char *argv[])

{

int sockfd;

struct sockaddr_un addr;

char *str;

memset(&addr, 0, sizeof(struct sockaddr_un));

/* Очищаем структуру с адресом */

addr.sun_family = AF_UNIX; /* Адрес домена UNIX */

/* Бит addr.sun_path[0] уже был обнулен вызовом memset() */

strncpy(&addr.sun_path[1], "xyz", sizeof(addr.sun_path) — 2);

/* Абстрактное имя "xyz", за которым следуют нулевые байты */

sockfd = socket(AF_UNIX, SOCK_STREAM, 0);

if (sockfd == -1)

errExit("socket");

if (bind(sockfd, (struct sockaddr *) &addr,

sizeof(sa_family_t) + strlen(str) + 1) == -1)

errExit("bind");

sleep(60);

exit(EXIT_SUCCESS);

}

Из файла sockets/us_abstract_bind.c

Идентификация абстрактных имен сокетов с помощью начального нулевого байта может иметь необычные последствия. Представьте, что переменная name указывает на строку нулевой длины; попытаемся привязать сокет домена UNIX к полю sun_path, инициализированному следующим образом:

strncpy(addr.sun_path, name, sizeof(addr.sun_path) — 1);

В Linux таким манером мы непреднамеренно создадим для сокета абстрактную привязку. Этот код можно считать ошибочным. В других реализациях UNIX последующий вызов bind() завершится ошибкой.

53.7. Резюме

Сокеты UNIX-домена позволяют приложениям взаимодействовать на одном и том же компьютере. Эти сокеты могут быть потоковыми и датаграммными.

Сокеты домена UNIX идентифицируются по имени в файловой системе. Доступ к сокету может регулироваться с помощью прав доступа к соответствующему файлу.

Системный вызов socketpair() создает пару сокетов домена UNIX, соединенных между собой. Это позволяет избежать сразу нескольких системных вызовов для операций создания, привязки и подключения. В своем использовании такие сокеты обычно похожи на именованный канал: создав пару сокетов, процесс генерирует поток, который наследует ссылающиеся на них дескрипторы.

Абстрактное пространство имен сокетов (доступное только в Linux) позволяет привязывать сокет домена UNIX к имени, не имеющему отношения к файловой системе.

Дополнительная информация

Ознакомьтесь с источниками, приведенными в разделе 55.14.

53.8. Упражнения

53.1. В разделе 53.3 отмечалось, что датаграммные сокеты домена UNIX являются надежными. Напишите программу, которая показывает следующее: отправитель блокируется, если шлет сообщения быстрее, чем получатель может их прочитать, и остается заблокированным, пока получатель читает отложенные датаграммы.

53.2. Перепишите программы us_xfr_sv.c (см. листинг 53.3) и us_xfr_cl.c (см. листинг 53.4) с помощью абстрактного пространства имен сокетов (см. раздел 53.6).

53.3. Заново реализуйте клиент-серверное приложение для генерирования числовых последовательностей (см. раздел 44.8), задействуя потоковые сокеты домена UNIX.

53.4. Представьте: мы создали два датаграммных сокета в домене UNIX, привязанных к путям /somepath/a и /somepath/b, и соединили их друг с другом. Что произойдет, если мы создадим третий датаграммный сокет и попытаемся с его помощью передать сообщение сокету /somepath/a (с помощью вызова sendto())? Напишите программу, которая отвечает на этот вопрос. По возможности проверьте, как будет вести себя данная программа в других UNIX-системах.

<p>54. Сокеты: основы сетей TCP/IP</p>
Перейти на страницу:

Похожие книги