Уильям Стивенс - UNIX: разработка сетевых приложений
- Название:UNIX: разработка сетевых приложений
- Автор:
- Жанр:
- Издательство:Питер
- Год:2007
- Город:Санкт-Петербург
- ISBN:5-94723-991-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Уильям Стивенс - UNIX: разработка сетевых приложений краткое содержание
Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.
UNIX: разработка сетевых приложений - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
66 if ((nwritten = write(STDOUT_FILENO, froptr, n)) < 0) {
67 if (errno != EWOULDBLOCK)
68 err_sys("write error to stdout");
69 } else {
70 fprintf(stderr, "%s: wrote %d bytes to stdout\n",
71 gf_time(), nwritten);
72 froptr += nwritten; /* только что полученное из функции write
число */
73 if (froptr == friptr)
74 froptr = friptr - fr; /* назад к началу буфера */
75 }
76 }
77 if (FD_ISSET(sockfd, &wset) && ((n - toiptr - tooptr) > 0)) {
78 if ((nwritten = write(sockfd, tooptr, n)) < 0) {
79 if (errno != EWOULDBLOCK)
80 err_sys("write error to socket");
81 } else {
82 fprintf(stderr, "%s: wrote %d bytes to socket\n",
83 gf_time(), nwritten);
84 tooptr += nwritten; /* только что полученное из функции write
число */
85 if (tooptr == toiptr) {
86 toiptr - tooptr = to; /* назад к началу буфера */
87 if (stdineof)
88 Shutdown(sockfd, SHUT_WR); /* посылаем FIN */
89 }
90 }
91 }
92 }
93 }
65-68
Если есть возможность записи в стандартный поток вывода и число байтов для записи больше нуля, вызывается функция write
. Если возвращается ошибка EWOULDBLOCK
, ничего не происходит. Обратите внимание, что это условие возможно, поскольку код в конце предыдущей части функции включает бит в наборе флагов записи для стандартного потока вывода, когда не известно, успешно выполнилась функция write
или нет.
68-74
Если функция write
выполняется успешно, froptr
увеличивается на число записанных байтов. Если указатель вывода стал равен указателю ввода, оба указателя переустанавливаются на начало буфера.
76-90
Эта часть кода аналогична коду, только что описанному для записи в стандартный поток вывода. Единственное отличие состоит в том, что когда указатель вывода доходит до указателя ввода, не только оба указателя переустанавливаются в начало буфера, но и появляется возможность отправить серверу сегмент FIN.
Теперь мы проверим работу этой функции и операций неблокируемого ввода-вывода. В листинге 16.4 показана наша функция gf_time
, вызываемая из функции str_cli
.
Листинг 16.4. Функция gf_time: возвращение указателя на строку времени
//lib/gf_time.c
1 #include "unp.h"
2 #include
3 char*
4 gf_time(void)
5 {
6 struct timeval tv;
7 static char str[30];
8 char *ptr;
9 if (gettimeofday(&tv, NULL) < 0)
10 err_sys("gettimeofday error");
11 ptr = ctime(&tv.tv_sec);
12 strcpy(str, &ptr[11]);
13 /* Fri Sep 13 00:00:00 1986\n\0 */
14 /* 0123456789012345678901234 5 */
15 snprintf(str + 8, sizeof(str) - 8, ".%06ld", tv.tv_usec);
15 return (str);
17 }
Эта функция возвращает строку, содержащую текущее время с точностью до микросекунд, в таком формате:
12:34:56.123456
Здесь специально используется тот же формат, что и для отметок времени, которые выводятся программой tcpdump
. Обратите внимание, что все вызовы функции fprintf
в нашей функции str_cli
записывают данные в стандартный поток сообщений об ошибках, позволяя нам отделить данные стандартного потока вывода (строки, отраженные сервером) от наших диагностических данных. Затем мы можем запустить наш клиент и функцию tcpdump
, получить эти диагностические данные вместе с результатом функции tcpdump
и отсортировать вместе два вида выходных данных в порядке их получения. Это позволит нам увидеть, что происходит в нашей программе, и соотнести это с действиями TCP.
Например, сначала мы запускаем функцию tcpdump
на нашем узле solaris
, собирая только сегменты TCP, идущие к порту 7 или от него (эхо-сервер), и сохраняем выходные данные в файле, который называется tcpd
:
solaris % tcpdump -w tcpd tcp and port 7
Затем мы запускаем клиент TCP на этом узле и указываем сервер на узле linux
:
solaris % tcpcli02 192.168.1.10 < 2000.lines > out 2> diag
Стандартный поток ввода — это файл 2000.lines
, тот же файл, что мы использовали для листинга 6.2. Стандартный поток вывода перенаправляется в файл out
, а стандартный поток сообщений об ошибках — в файл diag
. По завершении мы запускаем:
solaris % diff 2000.lines out
чтобы убедиться, что отраженные строки идентичны введенным строкам. Наконец, мы прекращаем выполнение функции tcpdump
нажатием соответствующей клавиши терминала, после чего выводим записи функции tcpdump
, сортируя их по времени получения вместе с данными диагностики, полученными от клиента. В листинге 16.5 показана первая часть этого результата.
Листинг 16.5. Отсортированный вывод функции tcpdump и данных диагностики
solaris % tcpdump -r tcpd -N | sort diag -
10:18:34.486392 solaris.33621 > linux.echo: S 1802738644:1802738644(0) win 8760
10:18:34.488278 linux.echo > solaris.33621: S 3212986316 3212986316(0) ack 1802738645 win 8760
10:18:34.488490 solaris.33621 > linux.echo: . ack 1 win 8760
10:18:34.491482: read 4096 bytes from stdin
10:18:34.518663 solaris.33621 > linux.echo: P 1461(1460) ack 1 win 8760
10:18:34.519016: wrote 4096 bytes to socket
10:18:34.528529 linux echo > solaris.33621. P 1:1461(1460) ack 1461 win 8760
10:18:34 528785 solaris.33621 > linux.echo: . 1461 2921(1460) ack 1461 win 8760
10:18:34.528900 solaris.33621 > linux echo: P 2921:4097(1176) ack 1461 win 8760
10:18:34.528958 solaris 33621 > linux.echo: ack 1461 win 8760
10:18:34.536193 linux echo: > solaris.33621: . 1461:2921(1460) ack 4097 win 8760
10:18:34.536697 linux.echo: > solaris.33621: P 2921.3509(588) ack 4097 win 8760
10:18.34.544636: read 4096 bytes from stdin 10:18:34.568505: read 3508 bytes from socket
10:18:34.580373 solaris 33621 > linux.echo: . ack 3509 win 8760
10:18:34.582244 linux.echo > solaris.33621: P 3509.4097(588) ack 4097 win 8760
10:18:34.593354: wrote 3508 bytes to stdout
10:18:34.617272 solaris.33621 > linux.echo: P 4097.5557(1460) ack 4097 win 8760
10:18:34.617610 solaris 33621 > linux.echo: P 5557:7017(1460) ack 4097 win 8760
10:18:34.617908 solaris.33621 > linux.echo: P 7017.8193(1176) ack 4097 win 8760
10:18:34.618062: wrote 4096 bytes to socket
10:18:34.623310 linux.echo > solaris.33621: . ack 8193 win 8760
10:18:34.626129 linux.echo > solaris.33621: . 4097.5557(1460) ack 8193 win 8760
10:18:34.626339 solaris.33621 > linux.echo: . ack 5557 win 8760
10:18:34.626611 linux.echo > solaris.33621: P 5557:6145(588) ack 8193 win 8760
10:18:34.628396 linux.echo > solaris.33621: 6145:7605(1460) ack 8193 win 8760
10:18:34.643524: read 4096 bytes from stdin 10:18:34.667305. read 2636 bytes from socket
10:18:34.670324 solaris.33621 > linux echo: . ack 7605 win 8760
10:18:34.672221 linux.echo > solaris.33621: P 7605.8193(588) ack 8193 win 8760
10:18:34.691039: wrote 2636 bytes to stdout
Мы удалили записи ( DF
) из сегментов, отправленных Solaris, означающие, что устанавливается бит DF (он используется для определения величины транспортной MTU).
Используя этот вывод, мы можем нарисовать временную диаграмму происходящих событий (рис. 16.3). На этой диаграмме представлены события в различные моменты времени, причем ориентация диаграммы такова, что более поздние события расположены ниже на странице.

Рис. 16.3. Временная диаграмма событий для примера неблокируемого ввода
Читать дальшеИнтервал:
Закладка: