Чтение онлайн

ЖАНРЫ

UNIX: разработка сетевых приложений
Шрифт:

Два созданных сокета не имеют имен. Это значит, что не было неявного вызова функции

bind
.

Результат выполнения функции

socketpair
с аргументом type, равным
SOCK_STREAM
, называется потоковым каналом( stream pipe). Потоковый канал является аналогом обычного канала Unix (который создается функцией
pipe
), но он двусторонний, что позволяет использовать оба дескриптора и для чтения, и для записи. Потоковый канал, созданный функцией
socketpair
, изображен на рис. 15.1.

ПРИМЕЧАНИЕ

POSIX

не требует поддержки двусторонних каналов. В SVR4 функция pipe возвращает два двусторонних дескриптора, в то время как ядра, происходящие от Беркли, традиционно возвращают односторонние дескрипторы (см. рис. 17.31 [112]).

15.4. Функции сокетов

Функции сокетов применяются к доменным сокетам Unix с учетом некоторых особенностей и ограничений. Далее мы перечисляем требования POSIX, указывая, где они применимы. Отметим, что на сегодняшний день не все реализации соответствуют этим требованиям.

1. Права доступа к файлу по умолчанию для полного имени, созданного функцией

bind
, задаются значением 0777 (чтение, запись и выполнение данного файла разрешены владельцу файла, группе пользователей, в которую он входит, и всем остальным пользователям) и могут быть изменены в соответствии с текущим значением
umask
.

2. Имя, связанное с доменным сокетом Unix, должно быть абсолютным, а не относительным именем. Причина, по которой нужно избегать относительного имени, в том, что в таком случае разрешение имени зависит от текущего рабочего каталога вызывающего процесса. То есть если сервер связывается с относительным именем, клиент должен находиться в том же каталоге, что и сервер (или должен знать этот каталог), для того чтобы вызов клиентом функции

connect
или
sendto
был успешным.

ПРИМЕЧАНИЕ

В POSIX сказано, что связывание относительного имени с доменным сокетом Unix приводит к непредсказуемым результатам.

3. Полное имя, заданное в вызове функции

connect
, должно быть именем, в настоящий момент связанным с открытым доменным сокетом Unix того же типа (потоковым или дейтаграммным). Ошибка происходит в следующих случаях: если имя существует, но не является сокетом; если имя существует и является сокетом, но ни один открытый дескриптор с ним не связан; если имя существует и является открытым сокетом, но имеет неверный тип (то есть потоковый доменный сокет Unix не может соединиться с именем, связанным с дейтаграммным доменным сокетом Unix, и наоборот).

4. С функцией

connect
доменного сокета Unix связана такая же проверка прав доступа, какая имеет место при вызове функции open для доступа к файлу только на запись.

5. Потоковые доменные сокеты Unix аналогичны сокетам TCP: они предоставляют интерфейс байтового потока без границ записей.

6. Если при вызове функции connect для потокового доменного сокета Unix обнаруживается, что очередь прослушиваемого сокета переполнена (см. раздел 4.5), немедленно возвращается ошибка

ECONNREFUSED
. В этом отличие от сокета TCP: прослушиваемый сокет TCP игнорирует приходящий сегмент SYN, если очередь сокета заполнена, благодаря чему стеком клиента выполняется несколько попыток отправки сегмента SYN.

7. Дейтаграммные доменные сокеты Unix аналогичны сокетам UDP: они предоставляют ненадежный сервис дейтаграмм,

сохраняющий границы записей.

8. В отличие от сокетов UDP, при отправке дейтаграммы на неприсоединенный дейтаграммный доменный сокет Unix с сокетом не связывается полное имя. (Вспомните, что отправка дейтаграммы UDP на неприсоединенный сокет UDP заставляет динамически назначаемый порт связываться с сокетом.) Это означает, что получатель дейтаграммы не будет иметь возможности отправить ответ, если отправитель не связал со своим сокетом полное имя. Аналогично, в отличие от TCP и UDP, при вызове функции

connect
для дейтаграммного доменного сокета Unix с сокетом не связывается полное имя.

15.5. Клиент и сервер потокового доменного протокола Unix

Теперь мы перепишем наш эхо-клиент и эхо-сервер TCP из главы 5 с использованием доменных сокетов Unix. В листинге 15.3 показан сервер, который является модификацией сервера из листинга 5.9 и использует потоковый доменный протокол Unix вместо протокола TCP.

Листинг 15.3. Эхо-сервер потокового доменного протокола Unix

//unixdomain/unixstrserv01.c

1 #include "unp.h"

2 int

3 main(int argc, char **argv)

4 {

5 int listenfd, connfd;

6 pid_t childpid;

7 socklen_t clilen;

8 struct sockaddr_un cliaddr, servaddr;

9 void sig_chld(int);

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

11 unlink(UNIXSTR_PATH);

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

13 servaddr.sun_family = AF_LOCAL;

14 strcpy(servaddr.sun_path, UNIXSTR_PATH);

15 Bind(listenfd, (SA*)&servaddr, sizeof(servaddr));

16 Listen(listenfd, LISTENQ);

17 Signal(SIGCHLD, sig_chld);

18 for (;;) {

19 clilen = sizeof(cliaddr);

20 if ((connfd = accept(listenfd, (SA*)&cliaddr, &clilen)) < 0) {

21 if (errno == EINTR)

22 continue; /* назад в for */

23 else

24 err_sys("accept error");

25 }

26 if ((childpid = Fork) == 0) { /* дочерний процесс */

27 Close(listenfd); /* закрывается прослушиваемый сокет */

28 str_echo(connfd); /* обработка запроса */

29 exit(0);

30 }

31 Close(connfd); /* родитель закрывает присоединенный сокет */

32 }

33 }

Поделиться с друзьями: