Уильям Стивенс - UNIX: разработка сетевых приложений
- Название:UNIX: разработка сетевых приложений
- Автор:
- Жанр:
- Издательство:Питер
- Год:2007
- Город:Санкт-Петербург
- ISBN:5-94723-991-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Уильям Стивенс - UNIX: разработка сетевых приложений краткое содержание
Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.
UNIX: разработка сетевых приложений - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
3. Прием входящих соединений: функция accept
. Если функция accept
вызывается для блокируемого сокета и новое соединение недоступно, процесс переводится в состояние ожидания.
Если функция accept
вызывается для неблокируемого сокета и новое соединение недоступно, возвращается ошибка EWOULDBLOCK
.
4. Инициирование исходящих соединений: функция connect
для TCP. (Вспомните, что функция connect может использоваться с UDP, но она не вызывает создания «реального» соединения — она лишь заставляет ядро сохранить IP-адрес и номер порта собеседника.) В разделе 2.5 мы показали, что установление соединения TCP включает трехэтапное рукопожатие и что функция connect не возвращает управление, пока клиент не получит сегмент ACK или SYN. Это значит, что функция TCP connect
всегда блокирует вызывающий процесс как минимум на время обращения (RTT) к серверу.
Если функция connect
вызывается для неблокируемого сокета TCP и соединение не может быть установлено немедленно, инициируется установление соединения (например, отправляется первый пакет трехэтапного рукопожатия TCP), но возвращается ошибка EINPROGRESS
. Обратите внимание, что эта ошибка отличается от ошибки, возвращаемой в первых трех сценариях. Также отметим, что некоторые соединения могут быть установлены немедленно, когда сервер находится на том же узле, что и клиент, поэтому даже в случае неблокируемого вызова функции connect
мы должны быть готовы к тому, что она успешно выполнится. Пример неблокируемой функции connect
мы покажем в разделе 16.3.
Традиционно System V возвращала для неблокируемой операции ввода-вывода, которую невозможно выполнить, ошибку EAGAIN, в то время как Беркли-реализации возвращали ошибку EWOULDBLOCK. Еще больше дело запутывается тем, что согласно POSIX.1 используется EAGAIN, в то время как в POSIX.1g определено, что используется EWOULDBLOCK. К счастью, большинство систем (включая SVR4 и 4.4BSD) определяют один и тот же код для этих двух ошибок (проверьте свой системный заголовочный файл ), поэтому не важно, какой из них использовать. В нашем тексте мы используем ошибку EWOULDBLOCK, как определяется в POSIX.
В разделе 6.2 мы представили различные модели ввода-вывода и сравнили неблокируемый ввод-вывод с другими моделями. В этой главе мы покажем примеры четырех типов операций и разработаем новый тип клиента, аналогичный веб-клиенту, инициирующий одновременно множество соединений TCP при помощи неблокируемой функции connect
.
16.2. Неблокируемые чтение и запись: функция str_cli (продолжение)
Мы снова возвращаемся к нашей функции str_cli
, которую мы обсуждали в разделах 5.5 и 6.4. Последняя ее версия, задействующая функцию select
, продолжает использовать блокируемый ввод-вывод. Например, если в стандартном устройстве ввода имеется некоторая строка, мы читаем ее с помощью функции fgets
и затем отправляем серверу с помощью функции writen
. Но вызов функции writen
может вызвать блокирование процесса, если буфер отправки сокета полон. В то время как мы заблокированы в вызове функции writen
, данные могут быть доступны для чтения из приемного буфера сокета. Аналогично, когда строка ввода доступна из сокета, мы можем заблокироваться в последующем вызове функции fputs
, если стандартный поток вывода работает медленнее, чем сеть. Наша цель в данном разделе — создать версию этой функции, использующую неблокируемый ввод-вывод. Блокирование будет предотвращено, благодаря чему в это время мы сможем сделать еще что-то полезное.
К сожалению, добавление неблокируемого ввода-вывода значительно усложняет управление буфером функции, поэтому мы будем представлять функцию частями. Мы также заменим вызовы функций из стандартной библиотеки ввода-вывода на обычные read
и write
. Это даст возможность отказаться от функций стандартной библиотеки ввода-вывода с неблокируемыми дескрипторами, так как их применение может привести к катастрофическим последствиям.
Мы работаем с двумя буферами: буфер to содержит данные, направляющиеся из стандартного потока ввода к серверу, а буфер fr
— данные, приходящие от сервера в стандартный поток вывода. На рис. 16.1 представлена организация буфера to
и указателей в буфере.

Рис. 16.1. Буфер, содержащий данные из стандартного потока ввода, идущие к сокету
Указатель toiptr
указывает на следующий байт, в который данные могут быть считаны из стандартного потока ввода. Указатель tooptr
указывает на следующий байт, который должен быть записан в сокет. Число байтов, которое может быть считано из стандартного потока ввода, равно &to[MAXLINE]
минус toiptr
. Как только значение tooptr
достигает toiptr
, оба указателя переустанавливаются на начало буфера.
На рис. 16.2 показана соответствующая организация буфера fr
. В листинге 16.1 [1] Все исходные коды программ, опубликованные в этой книге, вы можете найти по адресу http://www.piter.com.
представлена первая часть функции.

Рис. 16.2. Буфер, содержащий данные из сокета, идущие к стандартному устройству вывода
Листинг 16.1. Функция str_cli: первая часть, инициализация и вызов функции
//nonblock/strclinonb.c
1 #include "unp.h"
2 void
3 str_cli(FILE *fp, int sockfd)
4 {
5 int maxfdp1, val, stdineof;
6 ssize_t n, nwritten;
7 fd_set rset, wset;
8 char to[MAXLINE], fr[MAXLINE];
9 char *toiptr, *tooptr, *friptr, *froptr;
10 val = Fcntl(sockfd, F_GETFL, 0);
11 Fcntl(sockfd, F_SETFL, val | O_NONBLOCK);
12 val = Fcntl(STDIN_FILENO, F_SETFL, 0);
13 Fcntl(STDIN_FILENO, F_SETFL, val | O_NONBLOCK);
14 val = Fcntl(STDOUT_FILENO, F_SETFL, 0);
15 Fcntl(STDOUT_FILENO, F_SETFL, val | O_NONBLOCK);
16 toiptr = tooptr = to; /* инициализация указателей буфера */
17 friptr = froptr = fr;
18 stdineof = 0;
19 maxfdp1 = max(max(STDIN_FILENO, STDOUT_FILENO), sockfd) + 1;
20 for (;;) {
21 FD_ZERO(&rset);
22 FD_ZERO(&wset);
23 if (stdineof == 0 && toiptr < &to[MAXLINE])
24 FD_SET(STDIN_FILENO, &rset); /* чтение из стандартного потока
ввода */
25 if (friptr < &fr[MAXLINE])
26 FD_SET(sockfd, &rset); /* чтение из сокета */
27 if (tooptr != toiptr)
28 FD_SET(sockfd, &wset); /* данные для записи в сокет */
29 if (froptr != friptr)
30 FD_SET(STDOUT_FILENO, &wset); /* данные для записи в стандартный
поток вывода */
31 Select(maxfdp1, &rset, &wset, NULL, NULL);
10-15
Все три дескриптора делаются неблокируемыми при помощи функции fcntl
: сокет в направлении к серверу и от сервера, стандартный поток ввода и стандартный поток вывода.
Интервал:
Закладка: