Уильям Стивенс - UNIX: разработка сетевых приложений
- Название:UNIX: разработка сетевых приложений
- Автор:
- Жанр:
- Издательство:Питер
- Год:2007
- Город:Санкт-Петербург
- ISBN:5-94723-991-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Уильям Стивенс - UNIX: разработка сетевых приложений краткое содержание
Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.
UNIX: разработка сетевых приложений - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
int n;
if ((n = pthread_mutex_lock(&ndone_mutex)) != 0)
errno = n, err_sys("pthread_mutex_lock error");
В тексте книги вам будут встречаться функции, имена которые начинаются с заглавной буквы. Это наши собственные функции-обертки. Функция-обертка вызывает функцию, имеющую такое же имя, но начинающееся со строчной буквы.
При описании исходного кода, представленного в тексте книги, мы всегда ссылаемся на вызываемую функцию низшего уровня (например, socket), но не на функцию-обертку (например, Socket).
В качестве альтернативы мы можем определить новую функцию выдачи сообщений об ошибках, которая в качестве аргумента получает системный код ошибки. Однако проще всего текст будет выглядеть с использованием функции-обертки, определенной в листинге 1.4:
Pthread_mutex_lock(&ndone_mutex);
Листинг 1.4. Наша собственная функция-обертка для функции pthread_mutex_lock
//lib/wrappthread.c
72 void
73 Pthread_mutex_lock(pthread_mutex_t *mptr)
74 {
75 int n;
76 if ((n = pthread_mutex_lock(mptr)) == 0)
77 return;
78 errno = n;
79 err_sys("pthread_mutex_lock error");
80 }
Если аккуратно программировать на С, можно использовать макросы вместо функций, что обеспечивает небольшой выигрыш в производительности, однако функции- обертки редко, если вообще когда-нибудь бывают причиной недостаточной производительности программ.
Наш выбор — первая заглавная буква в названии функции — является компромиссом. Было предложено множество других стилей: подстановка префикса e перед названием функции (как сделано в [67, с. 182]), добавление _е к имени функции и т.д. Наш вариант кажется наименее отвлекающим внимание и одновременно дающим визуальное указание на то, что вызывается какая-то другая функция.
Эта технология имеет, кроме того, полезный побочный эффект: она позволяет проверять возникновение ошибок при выполнении таких функций, ошибки в которых часто остаются незамеченными, например close и listen.
На протяжении всей книги мы будем использовать эти функции-обертки, кроме тех случаев, когда нам нужно проверить ошибку явно и обрабатывать ее другим, отличным от прерывания программы, способом. Мы не приводим исходный код для всех наших собственных функций-оберток, но он свободно доступен в Интернете (см. предисловие).
Значение системной переменной Unix errno
Когда при выполнении функции Unix (например, одной из функций сокетов) происходит ошибка, глобальной переменной errno
присваивается положительное значение, указывающее на тип ошибки, а возвращаемое значение функции обычно равно -1. Наша функция err_sys
проверяет значение переменной errno
и печатает строку с соответствующим сообщением об ошибке (например, «Время соединения истекло», если значение переменной errno равно ETIMEDOUT
).
Переменная errno устанавливается равной определенному значению, только если при выполнении функции произошла какая-либо ошибка. Ее значение не определено, если функция не возвращает ошибки. Все положительные значения ошибок являются константами с именами в верхнем регистре, начинающимися на «E», и обычно определяются в заголовке . Ни одна ошибка не имеет кода 0.
Переменную errno нельзя хранить как глобальную переменную в случае множества потоков, у которых все глобальные переменные являются общими. О решении этой проблемы мы расскажем в главе 23.
На протяжении всего текста книги мы использовали фразы типа «функция connect возвращает ECONNREFUSED
» для сокращенного обозначения того, что при выполнении функции произошла ошибка (обычно при этом возвращаемое значение функции равно -1), и значение переменной errno
стало равным указанной константе.
1.5. Простой сервер времени и даты
Мы можем написать простую версию сервера TCP для определения времени и даты, который будет работать с клиентом, описанным в разделе 1.2. Мы используем функции-обертки, описанные в предыдущем разделе. Код сервера приведен в листинге 1.5.
Листинг 1.5. TCP-сервер времени и даты
//intro/daytimetcpsrv.c
1 #include "unp.h"
2 #include
3 int
4 main(int argc, char **argv)
5 {
6 int listenfd, connfd;
7 struct sockaddr_in servaddr;
8 char buff[MAXLINE];
9 time_t ticks;
10 listenfd = Socket(AF_INET, SOCK_STREAM, 0);
11 bzero(&servaddr, sizeof(servaddr));
12 servaddr.sin_family = AF_INET;
13 servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
14 servaddr.sin_port = htons(13); /* сервер времени и даты */
15 Bind(listenfd, (SA*)&servaddr, sizeof(servaddr));
16 Listen(listenfd, LISTENQ);
17 for (;;) {
18 connfd = Accept(listenfd, (SA*)NULL, NULL);
19 ticks = time(NULL);
20 snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
21 Write(connfd. buff, strlen(buff));
22 Close(connfd);
23 }
24 }
10
Создание сокета TCP выполняется так же, как и в клиентском коде.
11-15
Заранее известный порт сервера (13 в случае сервера времени и даты) связывается с сокетом путем заполнения структуры адреса интернет-сокета и вызова функции bind
. Мы задаем IP-адрес как INADDR_ANY
, что позволяет серверу принимать соединение клиента на любом интерфейсе в том случае, если узел сервера имеет несколько интерфейсов. Далее мы рассмотрим, как можно ограничить прием соединений одним-единственным интерфейсом.
16
С помощью вызова функции listen
сокет преобразуется в прослушиваемый, то есть такой, на котором ядро принимает входящие соединения от клиентов. Эти три этапа, socket
, bind
и listen
, обычны для любого сервера TCP при создании того, что мы называем прослушиваемым дескриптором ( listening descriptor ) (в нашем примере это переменная listenfd
).
Константа LISTENQ
взята из нашего заголовочного файла unp.h
. Она задает максимальное количество клиентских соединений, которые ядро ставит в очередь на прослушиваемом сокете. Более подробно мы расскажем о таких очередях в разделе 4.5.
17-21
Обычно процесс сервера блокируется при вызове функции accept
, ожидая принятия подключения клиента. Для установки TCP-соединения используется трехэтапное рукопожатие ( three-way handshake ). Когда рукопожатие состоялось, функция accept возвращает значение, и это значение является новым дескриптором ( connfd
), который называется присоединенным дескриптором ( connected descriptor ). Этот новый дескриптор используется для связи с новым клиентом. Новый дескриптор возвращается функцией accept
для каждого клиента, соединяющегося с нашим сервером.
Стиль, используемый в книге для обозначения бесконечного цикла, выглядит так:
Читать дальшеИнтервал:
Закладка: