Уильям Стивенс - UNIX: разработка сетевых приложений
- Название:UNIX: разработка сетевых приложений
- Автор:
- Жанр:
- Издательство:Питер
- Год:2007
- Город:Санкт-Петербург
- ISBN:5-94723-991-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Уильям Стивенс - UNIX: разработка сетевых приложений краткое содержание
Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.
UNIX: разработка сетевых приложений - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
В этой программе, состоящей из 27 строк, есть много важных особенностей, нуждающихся в обсуждении. Мы кратко рассмотрим их на тот случай, если это первая сетевая программа, с которой вы встретились, а более подробные сведения по соответствующим вопросам вы сможете получить в других главах.
1
Мы подключаем наш собственный заголовочный файл, unp.h
, текст которого приведен в разделе Г.1. Этот заголовочный файл, в свою очередь, подключает различные системные заголовочные файлы, которые необходимы большинству сетевых программ, и определяет используемые нами константы (например, MAXLINE
).
2-3
Определение функции main
вместе с аргументами командной строки. Везде в данной книге при написании кода подразумевалось, что для его компиляции должен использоваться компилятор ANSI С (American National Standards Institute — Национальный институт стандартизации США), который также называют ISO С.
10-11
Функция socket
создает потоковый сокет ( SOCK_STREAM
) Интернета (AF_INET) — это красивое название для обычного TCP-сокета). Функция возвращает дескриптор (небольшое целое число), который мы используем для идентификации сокета во всех последующих вызовах (например, connect
и read
).
Оператор if содержит вызов функции socket, присваивание возвращаемого значения переменной sockfd и последующую проверку, является ли это присвоенное значение меньшим нуля. Мы могли разбить этот оператор на два оператора С следующим образом:
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
но использованная в листинге 1.1 запись является типичным для языка С способом объединения двух строк. Поскольку в языке С оператор «меньше» (<) имеет более высокий приоритет, чем оператор присваивания, необходимо заключить в скобки операции присваивания и вызова функции (как это и сделано в листинге 1.1, в строке 10). Между двумя открывающими скобками мы всегда вставляем пробел как указание на то, что левая часть операции сравнения содержит также операцию присваивания. (Этот стиль позаимствован из исходного кода Minix [120].) Мы используем этот же прием в операторе while дальше в нашей программе.
Мы будем встречать множество различных вариантов использования термина сокет ( socket ). Во-первых, используемый нами API называется API сокетов . Во-вторых, в предыдущем абзаце мы упоминали функцию socket
, которая входит в API сокетов. В-третьих, там же мы ссылались и на «сокет TCP», который является синонимом конечной точки TCP ( TCP endpoint ).
Если вызов функции socket оказывается неудачным, мы прерываем выполнение программы с помощью вызова функции err_sys.
Она выдает сообщение об ошибке с ее описанием (например, «Протокол не поддерживается» — одна из возможных ошибок функции socket
) и прерывает выполнение процесса. Эта функция создана нами, как и некоторые другие, начинающиеся с err_
. Мы будем широко использовать их в примерах в последующих главах. Описание функций приводится в разделе Г.4.
12-16
Мы заполняем структуру адреса сокета Интернета (структура типа sockaddr_in
с именем servaddr
) IP-адресом и номером порта сервера. Сначала мы инициализируем всю структуру нулями, используя функцию bzero
, затем устанавливаем номер порта в 13 (который является номером заранее известного порта ( well-known port ) сервера времени и даты на любом узле TCP/IP, поддерживающем соответствующую службу — см. табл. 2.1), после чего устанавливаем IP-адрес равным значению, определенному первым аргументом командной строки ( argv[1]
). В этой структуре поля IP-адреса и номера порта должны иметь определенный формат: мы вызываем библиотечную функцию htons
(host to network short), чтобы преобразовать двоичный номер порта в требуемый формат, и вызываем библиотечную функцию inet_pton
(presentation to numeric), чтобы преобразовать аргумент командной строки в символах ASCII (например, 206.168.112.96
при выполнении данного примера) в двоичный формат.
Функция bzero не является функцией ANSI С. Она происходит от более раннего кода сетевого программирования Беркли. Тем не менее мы используем именно ее, а не функцию ANSI С memset, потому что с функцией bzero работать проще: она вызывается с двумя аргументами, a memset — с тремя. Почти каждый производитель, поддерживающий API сокетов, также реализует и функцию bzero, а если и не реализует, мы определяем ее через макрос в нашем заголовочном файле unp.h.
Автор [112] в первом издании сделал десять ошибок, поменяв местами аргументы memset. Компилятор С не может распознать эту ошибку, поскольку оба аргумента принадлежат одному типу. В действительности второй аргумент принадлежит типу int, а третий — size_t — обычно имеет тип unsigned int (то есть целое без знака), но заданные значения, соответственно, 0 и 16, являются допустимыми для обоих типов аргумента. Вызов функции memset все равно осуществлялся, но реально функция ничего не делала, поскольку задавалось нулевое число инициализируемых байтов. Программа работала, потому что только некоторые функции сокетов действительно требуют, чтобы последние 8 байт структуры адреса сокета Интернета были установлены в 0. Тем не менее это ошибка, и ее можно избежать при использовании функции bzero, поскольку перестановка двух аргументов функции bzero всегда будет выявлена компилятором С, если используются прототипы функций.
Возможно, вы впервые встречаете функцию inet_pton. Она появилась вместе с протоколом IPv6 (о котором более подробно мы поговорим в приложении А). В старых программах для преобразования точечно-десятичной записи (dotted-decimal string) ASCII в необходимый формат использовалась функция inet_addr, но у нее есть ряд ограничений, которых не имеет функция inet_pton. Не беспокойтесь, если ваша система (еще) не поддерживает эту функцию; реализация ее приведена в разделе 3.7.
17-18
Функция connect
, применяемая к сокету TCP, устанавливает соединение по протоколу TCP с сервером, адрес сокета которого содержится в структуре, на которую указывает второй аргумент. Мы также должны задать длину структуры адреса сокета в качестве третьего аргумента функции connect
, а для структур адреса интернет-сокета мы всегда предоставляем вычисление длины компилятору, используя оператор С sizeof
.
В заголовочном файле unp.h мы используем директиву #define SA, чтобы определить SA как struct sockaddr, что соответствует общей структуре адреса сокета. Каждый раз, когда одна из функций сокетов требует указателя на структуру адреса сокета, этот указатель должен быть преобразован к указателю на общую структуру адреса сокета. Это происходит потому, что функции сокетов появились раньше, чем стандарт ANSI С. Соответственно, тип указателя void* не был доступен в начале 80-х, когда эти функции были разработаны. Проблема состоит в том, что "struct sockaddr" занимает 15 символов и часто заставляет выходить строку исходного кода за правую границу экрана (или за страницу книги), поэтому мы сократили ее до SA. Более подробно мы исследуем общие структуры адресов сокетов на примере листинга 3.2.
Читать дальшеИнтервал:
Закладка: