Книга: Разработка приложений в среде Linux. Второе издание

17.5.7. Ожидание TCP-соединений

17.5.7. Ожидание TCP-соединений

Ожидание соединений TCP происходит почти идентично ожиданию соединений домена Unix. Единственные различия заключаются в семействах протоколов и адресов. Ниже показан вариант примера сервера домена Unix, который работает через сокеты TCP.

 1: /* tserver.с */
 2:
 3: /* Ожидает соединение на порте 4321. Как только соединение установлено,
 4:    из сокета в stdout копируются данные до тех пор, пока вторая
 5:    сторона не закроет соединение. Затем ожидает следующее соединение
 6:    с сокетом. */
 7:
 8: #include <arpa/inet.h>
 9: #include <netdb.h>
10: #include <netinet/in.h>
11: #include <stdio.h>
12: #include <string.h>
13: #include <sys/socket.h>
14: #include <unistd.h>
15:
16: #include "sockutil.h" /* некоторые служебные функции */
17:
18: int main(void) {
19:  int sock, conn, i, rc;
20:  struct sockaddr address;
21:  size_t addrLength = sizeof(address);
22:  struct addrinfo hints, * addr;
23:
24:  memset(&hints, 0, sizeof(hints));
25:
26:  hints.ai_socktype = SOCK_STREAM;
27:  hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
28:  if ((rc = getaddrinfo(NULL, "4321", &hints, &addr))) {
29:   fprintf(stderr, "сбой поиска имени хоста: %sn",
30:   gai_strerror(rc));
31:   return 1;
32:  }
33:
34:  if ((sock = socket(addr->ai_family, addr->ai_socktype,
35:   addr->ai_protocol)) < 0)
36:   die("socket");
37:
38:  /* Позволяет ядру повторно использовать адрес сокета. Это разрешает
39:     нам запускать программу два раза подряд, не ожидая пока истечет
40:     время для кортежа (ip-адрес, порт). */
41:  i = 1;
42:  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
43:
44:  if (bind(sock, addr->ai_addr, addr->ai_addrlen))
45:   die("bind");
46:
47:  freeaddrinfo(addr);
48:
49:  if (listen(sock, 5))
50:   die("listen");
51:
52:  while ((conn = accept(sock, (struct sockaddr *) &address,
53:   &addrLength)) >=0) {
54:   printf("----получение данныхn");
55:   copyData(conn, 1);
56:   printf("----готовоn");
57:   close(conn);
58:  }
59:
60:  if (conn < 0)
61:   die("accept");
62:
63:  close(sock);
64:  return 0;
65: }

Обратите внимание на то, что IP-адрес, привязанный к сокету, указывает номер порта 4321, но не IP-адрес. Это предоставляет ядру возможность при необходимости воспользоваться локальным IP-адресом.

Код в строках 41–42 требует дополнительного объяснения.

41: i = 1;
42: setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));

Linux-реализация TCP, как и в остальных системах Unix, вводит ограничения на то, насколько скоро можно повторно использовать кортеж (локальный хост, локальный порт)[136]. Этот код устанавливает опцию на сокет, которая обходит это ограничение и позволяет дважды запускать сервер за короткий период времени. По сходной причине сервер-пример сокета домена Unix удаляет любой существующий файл сокета, прежде чем вызывать bind().

Функция setsockopt() позволяет устанавливать множество специальных опций для сокета и протокола:

#include <sys/socket.h>
int setsockopt(int sock, int level, int option,
 const void * valptr, int vallength);

Первый аргумент — это сокет, для которого определяется опция. Второй аргумент, level, указывает тип устанавливаемой опции. В нашем сервере используется SOL_SOCKET, что указывает на установку опции обобщенного сокета. Параметр option определяет опцию, которая подлежит изменению. Указатель на новое значение опции передается через valptr, а размер значения, на которое указывает valptr, передается как vallength. Для нашего сервера применяется указатель на ненулевое целое число, которое вводит в действие опцию SO_REUSEADDR.

Оглавление книги


Генерация: 1.583. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз