Книга: UNIX: разработка сетевых приложений
Пример
Разделы на этой странице:
Пример
Теперь мы модифицируем наш эхо-сервер TCP таким образом, чтобы выводить полученный маршрут от отправителя, а эхо-клиент TCP — так, чтобы маршрут от отправителя можно было задавать. В листинге 27.4 показан код эхо-клиента TCP.
Листинг 27.4. Эхо-клиент TCP, задающий маршрут от отправителя
//ipopts/tcpcli01.c
1 #include "unp.h"
2 int
3 main(int argc, char **argv)
4 {
5 int c, sockfd, len = 0;
6 u_char *ptr = NULL;
7 struct addrinfo *ai;
8 if (argc < 2)
9 err_quit("usage: tcpcli01 [ -[gG] <hostname> ... ] <hostname>");
10 opterr = 0; /* отключаем запись сообщений getopt() в stderr */
11 while ((с = getopt(argc, argv, "gG")) != -1) {
12 switch (c) {
13 case 'g': /* свободный маршрут от отправителя */
14 if (ptr)
15 err_quit("can't use both -g and -G");
16 ptr = inet_srcrt_init(0);
17 break;
18 case 'G': /* жесткий маршрут от отправителя */
19 if (ptr)
20 err_qint("can't use both -g and -G");
21 ptr = inet_srcrt_init(1);
22 break;
23 case '?':
24 err_quit("unrecognized option: %c", c);
25 }
26 }
27 if (ptr)
28 while (optind < argc-1)
29 len = inet_srcrt_add(argv[optind++]);
30 else if (optind < argc-1)
31 err_quit("need -g or -G to specify route");
32 if (optind != argc-1)
33 err_quit("missing <hostname>");
34 ai = Host_serv(argv[optind], SERV_PORT_STR, AF_INET, SOCK_STREAM);
35 sockfd = Socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
36 if (ptr) {
37 len = inet_srcrt_add(argv[optind]); /* получатель в конце */
38 Setsockopt(sockfd, IPPROTO_IP, IP_OPTIONS, ptr, len);
39 free(ptr);
40 }
41 Connect(sockfd, ai->ai_addr, ai->ai_addrlen);
42 str_cli(stdin, sockfd); /* вызов рабочей функции */
43 exit(0);
44 }
Обработка аргументов командной строки
12-26
Мы вызываем нашу функцию inet_srcrt_init
, чтобы инициализировать маршрут от отправителя. Тип маршрутизации указывается при помощи параметра -g
(свободная) или -G
(жесткая).
27-33
Если указатель ptr
установлен, значит, был указан параметр маршрутизации от отправителя, и все указанные промежуточные узлы добавляются к маршруту, подготовленному на предыдущем этапе функцией inet_srcrt_add
. Если же ptr
не установлен, но в командной строке еще есть аргументы, значит, пользователь задал маршрут, но не указал его тип. В этом случае программа завершает работу с сообщением об ошибке.
Обработка адреса получателя и создание сокета
34-35
Последний аргумент командной строки — это имя узла или адрес сервера в точечно-десятичной записи, который обрабатывается нашей функцией host_serv
. Мы не можем вызвать функцию tcp_connect
, так как должны задать маршрут от отправителя между вызовом функций socket
и connect
. Последняя инициирует трехэтапное рукопожатие, а нам нужно, чтобы сегмент SYN отправителя и все последующие пакеты проходили по одному и тому же маршруту.
36-42
Если маршрут от отправителя задан, следует добавить IP-адрес сервера в конец списка адресов (см. рис. 27.1). Функция setsockopt
устанавливает маршрут от отправителя для данного сокета. Затем мы вызываем функцию connect, а потом — нашу функцию str_cli
(см. листинг 5.4).
Наш TCP-сервер имеет много общего с кодом, показанным в листинге 5.9, но содержит следующие изменения.
Во-первых, мы выделяем место для параметров:
int len;
u_char *opts;
opts = Malloc(44);
Во-вторых, мы получаем параметры IP после вызова функции accept
, но перед вызовом функции fork
:
len = 44;
Getsockopt(connfd, IPPROTO_IP, IP_OPTIONS, opts, &len);
if (len > 0) {
printf("received IP options, len = %dn", len);
inet_srcrt_print(opts, len);
}
Если сегмент SYN, полученный от клиента, не содержит никаких параметров IP, переменная len
по завершении функции getsockopt
будет иметь нулевое значение (эта переменная относится к типу «значение-результат»). Как уже упоминалось, нам не нужно предпринимать какие-либо шаги для того, чтобы на стороне сервера использовался обращенный маршрут от отправителя: это делается автоматически без нашего участия [128, с. 931]. Вызывая функцию getsockopt
, мы просто получаем копию обращенного маршрута от отправителя. Если мы не хотим, чтобы TCP использовал этот маршрут, то после завершения функции accept следует вызвать функцию setsockopt
и задать нулевую длину (последний аргумент), тем самым удалив все используемые в текущий момент параметры IP. Но маршрут от отправителя тем не менее уже был использован в процессе трехэтапного рукопожатия при пересылке второго сегмента. Если мы уберем параметры маршрутизации, IP составит и будет использовать для пересылки последующих пакетов какой-либо другой маршрут.
Теперь мы покажем пример клиент-серверного взаимодействия при заданном маршруте от отправителя. Мы запускаем наш клиент на узле freebsd
следующим образом:
freebsd4 % tcpcli01 -g macosx freebsd4 macosx
Тем самым дейтаграммы IP отсылаются с узла freebsd
на узел macosx
, обратно на узел freebsd4
, и наконец, на macosx
, где запущен наш сервер. Две промежуточные системы freebsd4
и macosx
должны переправлять дейтаграммы и принимать дейтаграммы с маршрутизацией от отправителя, чтобы этот пример работал.
Когда соединение устанавливается, на стороне сервера выдается следующий результат:
macosx % tcpserv01
received IP options, len = 16
received LSRR, 172.24.37.94 172.24.37.78 172.24.37.94
Первый выведенный IP-адрес — это первый узел обратного маршрута (freebsd4
, как показано на рис. 27.2), а следующие два адреса идут в том порядке, который используется сервером для отправки дейтаграмм назад клиенту. Если мы понаблюдаем за процессом взаимодействия клиента и сервера с помощью программы tcpdump
, мы увидим, как используется параметр маршрутизации для каждой дейтаграммы в обоих направлениях.
ПРИМЕЧАНИЕ
К сожалению, действие параметра сокета IP_OPTIONS никогда не было документировано, поэтому вы можете увидеть различные вариации поведения в системах, не происходящих от исходного кода Беркли. Например, в системе Solaris 2.5 первый адрес, возвращаемый функцией getsockopt (см. рис. 27.2) — это не первый адрес в обращенном маршруте, а адрес собеседника. Тем не менее обратный маршрут, используемый TCP, будет корректен. Кроме того, в Solaris 2.5 всем параметрам маршрутизации предшествует четыре параметра NOP, что ограничивает параметр маршрутизации восемью IP-адресами, а не девятью, которые реально могли бы поместиться.
- Пример установочного скрипта
- Пример из практики
- ПРИМЕР ПРОСТОЙ ПРОГРАММЫ НА ЯЗЫКЕ СИ
- Примеры получения статистики
- Пример применения метода «пять почему»
- Пример 12-8. Частота встречаемости отдельных слов
- 1.2.5. Пример программы
- Пример 17-10. Блочный комментарий
- Примеры
- 2. Пример создания базового отношения в записи на псевдокоде
- Пример 9-8. Содержимое $* и $@, когда переменная $IFS -- пуста
- Часть I На примере денег