, но в последующих версиях ядра Linux оно может измениться.
Первый член
sun_family
должен содержать
AF_UNIX
для того, чтобы показать, что структура содержит адрес домена Unix. Параметр
sun_path
хранит путевое имя, которое нужно использовать для соединения. Если системным вызовам, относящимся к сокету, передается размер адреса, то передаваемая длина равна количеству символов в путевом имени плюс размер элемента
sun_family
. Параметр
sun_path
не обязательно должен заканчиваться
'\0'
, хотя обычно делают именно так.
17.4.2. Ожидание соединения
Как объяснялось выше, ожидание установки соединения на сокете домена Unix придерживается следующей процедуры: создание сокета, привязка адреса к сокету, перевод системы в режим ожидания соединений и принятие соединения.
Ниже показан пример простого сервера, который многократно принимает соединения с сокетом домена Unix (файл
sample-socket
в текущем каталоге) и считывает все данные из сокета, посылая их на стандартный вывод.
1: /* userver.c */
2:
3: /* Ожидает соединения на сокете ./sample-socket домена Unix.
4: После установки соединения копирует данные
5: из сокета в stdout до тех пор, пока вторая сторона не
6: закрывает соединение. Далее ожидает следующее соединение
7: с сокетом. */
8:
9: #include <stdio.h>
10: #include <sys/socket.h>
11: #include <sys/un.h>
12: #include <unistd.h>
13:
14: #include "sockutil.h" /* некоторые служебные функции */
15:
16: int main (void) {
17: struct sockaddr_un address;
18: int sock, conn;
19: size_t addrLength;
20:
21: if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
22: die("socket");
23:
24: /* Удалить все сокеты (или файлы), существовавшие ранее */
35: if (bind(sock, (struct sockaddr *) &address, addrLength))
36: die("bind");
37:
38: if (listen(sock, 5))
39: die("listen");
40:
41: while ((conn = accept(sock, (struct sockaddr *) &address,
42: &addrLength)) >=0) {
43: printf("----
получение данных\n");
44: copyData(conn, 1);
45: printf("---- готово\n");
46: close(conn);
47: }
48:
49: if (conn < 0)
50: die("accept");
51:
52: close(sock);
53: return 0;
54: }
Несмотря на небольшой размер приведенной программы, она хорошо иллюстрирует, как написать простой серверный процесс. Этот сервер является итеративным, поскольку он обрабатывает только одного клиента за раз. Можно создавать также параллельные серверы, управляющие несколькими клиентами одновременно [124] .
124
Исходя из условий реального мира, большинство серверных программ должны быть параллельными. Однако многие из них фактически созданы как итерационные сервера. Например, Web-серверы, в основном, обрабатывают только одно соединение за раз через данный процесс. Для того чтобы разрешить соединение нескольким клиентам, сервер организован в виде множества отдельных процессов. Это делает создание Web-сервера более простым. Если ошибка прерывает работу одного из таких процессов, она затрагивает только одно клиентское соединение.
Обратите внимание на то, что функция
unlink
вызывается до связывания сокета. Поскольку функция
bind
прекращает работу, если файл сокета уже существует, то этот шаг позволяет запускать программу более одного раза без необходимости удаления файла сокета вручную.
Серверный код приводит тип указателя
struct sockaddr_un
, передаваемого и в
bind
, и в
accept
, к
(struct sockaddr *)
. При прототипировании различных системных вызовов, относящихся к сокетам, предполагается, что они принимают указатель на
struct sockaddr
. Приведение типа предотвращает появление уведомлений от компилятора о несоответствии типов указателей.
17.4.3. Соединение с сервером
Процесс соединения с сервером через сокет домена Unix состоит из создания сокета и присоединения к требуемому адресу через функцию
connect
. Как только сокет присоединен, он может обрабатываться как любой другой файловый дескриптор.
Следующая программа подключается с тем же самым сокетом, который использовался в примере сервера, и копирует его стандартные входные данные на сервер.
1: /* uclient.c */
2:
3: /* Подключиться к сокету ./sample-socket домена Unix, скопировать stdin
4: в сокет, после этого выйти из программы. */
5:
6: #include <sys/socket.h>
7: #include <sys/un.h>
8: #include <unistd.h>
9:
10: #include "sockutil.h" /* некоторые служебные функции */