UNIX: разработка сетевых приложений
Вызов функций bind и getsocknameМы копируем аргумент командной строки, используя функцию12-18, чтобы избежать переполнения структуры, если полное имя слишком длинное. Поскольку мы инициализируем структуру нулем и затем вычитаем единицу из размера массиваstrncpy, мы знаем, что полное имя оканчивается нулем. Далее вызывается функцияsun_pathи мы используем макросbindдля вычисления длины аргумента функции. Затем мы вызываем функциюSUN_LEN, чтобы получить имя, которое было только что связано с сокетом, и выводим результат.getsocknameЕсли мы запустим программу в Solaris, то получим следующие результаты:
solaris % <b>umask</b> <i>сначала выводим наше значение umask</i>022 <i>оно отображается в восьмеричной системе</i>solaris % <b>unixbind /tmp/moose</b>bound name = /tmp/moose, returned len = 13solaris % <b>unixbind /tmp/moose</b> <i>снова запускаем программу</i>bound name = /tmp/moose, returned len = 13solaris % <b>ls -l /tmp/moose</b>srwxr-xr-x 1 andy staff 0 Aug 10 13:13 /tmp/moosesolaris % <b>ls -lF /tmp/foo.bar</b>srwxr-xr-x 1 andy staff 0 Aug 10 13:13 /tmp/moose=Сначала мы выводим наше значение
, поскольку в POSIX указано, что права доступа к создаваемому объекту определяются этим значением. Наше значение 022 выключает биты, разрешающие запись в файл для пользователей из группы (group-write) и прочих пользователей (other-write). Затем мы запускаем программу и видим, что длина, возвращаемая функциейumask, равна 13: один байт для элементаgetsockname, один байт для элементаsun_lenи 11 байт для полного имени (исключая завершающий нуль). Это пример аргумента типа «значение-результат», значение которого при завершении функции отличается от значения при вызове функции. Мы можем вывести полное имя, используя спецификатор форматаsun_familyфункции%s, поскольку полное имя, хранящееся вprintf, представляет собой завершающуюся нулем строку. Затем мы снова запускаем программу, чтобы проверить, что вызов функцииsun_pathудаляет соответствующий файл.unlinkМы запускаем команду
, чтобы увидеть биты разрешения для файла и тип файла. В Solaris (и большинстве версий Unix) тип файла — это сокет, что обозначается символом s. Мы также замечаем, что все девять битов разрешения включены, так как Solaris не изменяет принятые по умолчанию биты разрешения на наше значениеls -l. Наконец, мы снова запускаемumaskс параметромls, что заставляет Solaris добавить знак равенства (соответствующий типу «сокет») к полному имени.-FПРИМЕЧАНИЕИзначально значение umask не действовало на создаваемые процессами доменные сокеты Unix, но с течением времени производители исправили это упущение, чтобы устанавливаемые разрешения соответствовали ожиданиям разработчиков. Тем не менее все еще существуют системы, в которых разрешения доменного сокета могут не зависеть от значения umask. В других системах сокеты могут отображаться как каналы (символ р), а значок равенства при вызове ls -F может не отображаться вовсе. Однако поведение, демонстрируемое в нашем примере, является наиболее типичным.
15.3. Функция socketpair
Функция
создает два сокета, которые затем соединяются друг с другом. Эта функция применяется только к доменным сокетам Unix.socketpair#include <sys/socket.h>int socketpair(int <i>family</i>, int <i>type</i>, int <i>protocol</i>, int <i>sockfd</i>[2]);<i>Возвращает: ненулевое значение в случае успешного выполнения, -1 в случае ошибки</i>Аргумент
должен быть равенfamily, а аргументAF_LOCALдолжен быть нулевым. Однако аргумент type может быть равен какprotocol, так иSOCK_STREAM. Два дескриптора сокета создаются и возвращаются какSOCK_DGRAMиsockfd[0].sockfd[1]ПРИМЕЧАНИЕЭта функция аналогична функции Unix pipe: при ее вызове возвращаются два дескриптора, причем каждый дескриптор соединен с другим. Действительно, в Беркли-реализации внутреннее устройство функции pipe полностью аналогично функции socketpair [112, с. 253-254].
Два созданных сокета не имеют имен. Это значит, что не было неявного вызова функции
.bindРезультат выполнения функции
с аргументом type, равнымsocketpair, называется потоковым каналом (stream pipe). Потоковый канал является аналогом обычного канала Unix (который создается функциейSOCK_STREAM), но он двусторонний, что позволяет использовать оба дескриптора и для чтения, и для записи. Потоковый канал, созданный функциейpipe, изображен на рис. 15.1.socketpairПРИМЕЧАНИЕPOSIX не требует поддержки двусторонних каналов. В SVR4 функция pipe возвращает два двусторонних дескриптора, в то время как ядра, происходящие от Беркли, традиционно возвращают односторонние дескрипторы (см. рис. 17.31 [112]).
15.4. Функции сокетов
Функции сокетов применяются к доменным сокетам Unix с учетом некоторых особенностей и ограничений. Далее мы перечисляем требования POSIX, указывая, где они применимы. Отметим, что на сегодняшний день не все реализации соответствуют этим требованиям.
1. Права доступа к файлу по умолчанию для полного имени, созданного функцией
, задаются значением 0777 (чтение, запись и выполнение данного файла разрешены владельцу файла, группе пользователей, в которую он входит, и всем остальным пользователям) и могут быть изменены в соответствии с текущим значениемbind.umask2. Имя, связанное с доменным сокетом Unix, должно быть абсолютным, а не относительным именем. Причина, по которой нужно избегать относительного имени, в том, что в таком случае разрешение имени зависит от текущего рабочего каталога вызывающего процесса. То есть если сервер связывается с относительным именем, клиент должен находиться в том же каталоге, что и сервер (или должен знать этот каталог), для того чтобы вызов клиентом функции
илиconnectбыл успешным.sendto