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

12   if (cred.cmcred_ngroups == 0) {

13    printf("(no credentials returned)\n");

14   } else {

15    printf("PID of sender = %d\n", cred.cmcred_pid);

16    printf("real user ID = %d\n", cred.cmcred_uid);

17    printf("real group ID = %d\n", cred.cmcred_gid);

18    printf("effective user ID = %d\n", cred.cmcred_euid);

19    printf("%d groups:", cred.cmcred_ngroups - 1);

20    for (i = 1; i < cred.cmcred_ngroups; i++)

21     printf(" %d", cred.cmcred_groups[i]);

22    printf("\n");

23   }

24   Writen(sockfd, buf, n);

25  }

26  if (n < 0 && errno == EINTR)

27   goto again;

28  else if (n < 0)

29   err_sys("str_echo: read error");

30 }

11-23
 Если идентифицирующие данные возвращаются, они выводятся.

24-25
 Оставшаяся часть цикла не меняется. Этот код считывает строки от клиента и затем отправляет их обратно клиенту.

Наш клиент, представленный в листинге 15.4, остается практически неизменным. Мы добавляем передачу пустой структуры

cmsgcred
при вызове
sendmsg
, которая заполняется ядром.

Перед запуском клиента определим свои личные данные командой

id
:

freebsd % <b>id</b>

uid=1007(andy) gid=1007(andy) groups=1007(andy), 0(wheel)

Если мы запустим сервер в одном окне, а клиент в другом, то для сервера после однократного выполнения клиента получим представленный ниже вывод.

freebsd % <b>unixstrserv02</b>

PID of sender = 26881

real user ID = 1007

real group ID = 1007

effective user ID = 1007

2 groups: 1007 0

Информация выводится только после отправки клиентом данных серверу. Мы видим, что сведения соответствуют тем, которые были получены командой

id
.

15.9. Резюме

Доменные сокеты Unix являются альтернативой IPC, когда клиент и сервер находятся на одном узле. Преимущество использования доменных сокетов Unix перед некоторой формой IPC состоит в том, что используемый API практически идентичен клиент-серверному сетевому соединению. Преимущество использования доменных сокетов Unix перед TCP, когда клиент и сервер находятся на одном узле, заключается в повышенной производительности доменных сокетов Unix относительно TCP во многих реализациях.

Мы изменили наш эхо-сервер и эхо-клиент TCP и UDP для использования доменных протоколов Unix, и единственным главным отличием оказалась необходимость при помощи функции

bind
связывать полное имя с клиентским сокетом UDP так, чтобы серверу UDP было куда отправлять ответы.

Передача дескрипторов между клиентами и серверами, находящимися на одном узле, — это мощная технология, которая используется при работе с доменными сокетами Unix. Мы показали пример передачи дескриптора от дочернего процесса обратно родительскому процессу в разделе 15.7. В разделе 28.7 мы покажем пример, в котором клиент и сервер не будут родственными, а в разделе 30.9 — другой пример, когда дескриптор передается от родительского процесса дочернему.

Упражнения

1. Что произойдет, если доменный сервер Unix вызовет функцию

unlink
после вызова функции
bind
?

2. Что произойдет, если доменный сервер Unix при завершении не отсоединит с помощью функции

unlink
свое известное полное имя, а клиент будет пытаться с помощью функции
connect
соединиться с сервером через некоторое время после того, как тот завершит работу?

3. Измените листинг 11.5 так, чтобы после того как будет выведен адрес протокола собеседника, вызывалась бы функция

sleep(5)
, а также чтобы вывести число байтов, возвращаемых функцией
read
всякий раз, когда она возвращает положительное значение. Измените листинг 11.8 так, чтобы для каждого байта результата, отправляемого клиенту, вызывалась функция
write
. (Мы обсуждаем подобные изменения в решении упражнения 1.5.) Запустите клиент и сервер на одном узле, используя TCP. Сколько байтов считывает клиент с помощью функции
read
?

Запустите клиент и сервер на одном узле, используя доменный сокет Unix. Изменилось ли что-нибудь?

Теперь для сервера вместо функции write вызовите функцию

send
и задайте флаг
MSG_EOR
(чтобы выполнить это упражнение, вам нужно использовать Беркли-реализацию). Запустите клиент и сервер на одном узле, используя доменный сокет Unix. Изменилось ли что-нибудь?

4. Напишите программу, определяющую значения, показанные в табл. 4.6. Один из подходов — создать потоковый канал и затем с помощью функции

fork
разветвить родительский и дочерний процессы. Родительский процесс входит в цикл
for
, увеличивая на каждом шаге значение
backlog
от 0 до 14. Каждый раз при прохождении цикла родительский процесс сначала записывает значение
backlog
в потоковый канал. Дочерний процесс читает это значение, создает прослушиваемый сокет, связанный с адресом закольцовки, и присваивает
backlog
считанное значение. Затем дочерний процесс делает запись в потоковый канал просто для того, чтобы сообщить родительскому процессу о своей готовности. Затем родительский процесс пытается установить как можно больше соединений, задав предварительно аргумент функции
alarm
равным 2 с, поскольку при достижении предельного значения
backlog
вызов функции connect заблокируется, и отправляет еще раз сегмент
SYN
. Дочерний процесс никогда не вызывает функцию
accept
, что позволяет ядру установить в очередь все соединения с родительским процессом. Когда истекает время ожидания родительского процесса (аргумент функции
alarm
, в данном случае 2 с), по счетчику цикла он может определить, какая по счету функция
connect
соответствует предельному значению
backlog
. Затем родительский процесс закрывает свои сокеты и пишет следующее новое значение в потоковый канал для дочернего процесса. Когда дочерний процесс считывает новое значение, он закрывает прежний прослушиваемый сокет и создает новый, заново начиная процедуру.

176
{"b":"225366","o":1}
ЛитМир: бестселлеры месяца