17.4.2. Ожидание соединения

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:  /* Удалить все сокеты (или файлы), существовавшие ранее */

25:  unlink("./sample-socket");

26:

27:  address.sun_family = AF_UNIX; /* сокет домена Unix */

28:  strcpy(address.sun_path, "./sample-socket");

29:

30:  /* Общая длина адреса, включая элемент

31:     sun_family */

32:  addrLength = sizeof(address.sun_family) +

33:  strlen(address.sun_path);

34:

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("---- получение данных ");

44:   copyData(conn, 1);

45:   printf("---- готово ");

46:   close(conn);

47:  }

48:

49:  if (conn < 0)

50:   die("accept");

51:

52:  close(sock);

53:  return 0;

54: }

Несмотря на небольшой размер приведенной программы, она хорошо иллюстрирует, как написать простой серверный процесс. Этот сервер является итеративным, поскольку он обрабатывает только одного клиента за раз. Можно создавать также параллельные серверы, управляющие несколькими клиентами одновременно[124].

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

Серверный код приводит тип указателя struct sockaddr_un, передаваемого и в bind(), и в accept(), к (struct sockaddr *). При прототипировании различных системных вызовов, относящихся к сокетам, предполагается, что они принимают указатель на struct sockaddr. Приведение типа предотвращает появление уведомлений от компилятора о несоответствии типов указателей.