Уильям Стивенс - UNIX: разработка сетевых приложений
- Название:UNIX: разработка сетевых приложений
- Автор:
- Жанр:
- Издательство:Питер
- Год:2007
- Город:Санкт-Петербург
- ISBN:5-94723-991-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Уильям Стивенс - UNIX: разработка сетевых приложений краткое содержание
Новое издание книги, посвященной созданию веб-серверов, клиент-серверных приложений или любого другого сетевого программного обеспечения в операционной системе UNIX, — классическое руководство по сетевым программным интерфейсам, в частности сокетам. Оно основано на трудах Уильяма Стивенса и полностью переработано и обновлено двумя ведущими экспертами по сетевому программированию. В книгу включено описание ключевых современных стандартов, реализаций и методов, она содержит большое количество иллюстрирующих примеров и может использоваться как учебник по программированию в сетях, так и в качестве справочника для опытных программистов.
UNIX: разработка сетевых приложений - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
struct msghdr msg;
struct cmsghdr *cmsgptr;
/* заполнение структуры msg */
/* вызов recvmsg() */
for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL;
cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
if (cmsgptr->cmsg_level == ... &&
cmsgptr->cmsg_type == ...) {
u_char *ptr;
ptr = CMSG_DATA(cmsgptr);
/* обработка данных, на которые указывает ptr */
}
}
Макрос CMSG_FIRSTHDR
возвращает указатель на первый объект вспомогательных данных или пустой указатель, если в структуре msghdr
нет вспомогательных данных (или msg_control
является пустым указателем, или cmsg_len
меньше размера структуры cmsghdr
). Макрос CMSG_NXTHDR
возвращает пустой указатель, когда в буфере управления нет другого объекта вспомогательных данных.
Многие существующие реализации макроса CMSG_FIRSTHRD никогда не используют элемент msg_controllen и просто возвращают значение cmsg_control. В листинге 22.2 мы проверяем значение msg_controllen перед вызовом макроопределения.
Разница между макросами CMSG_LEN
и CMSG_SPACE
заключается в том, что первый возвращает длину объекта вместе с дополняющими нулями (это значение хранится в cmsg_len
), а последний возвращает длину собственно объекта (это значение может использоваться для динамического выделения памяти под объект).
14.7. Сколько данных находится в очереди?
Иногда требуется узнать, сколько данных находится в очереди для чтения данного сокета, не считывая эти данные. Для этого имеется три способа.
1. Если нашей целью не является блокирование в ядре (поскольку мы можем выполнять другие задачи, пока данные для чтения еще не готовы), может использоваться неблокируемый ввод-вывод. Мы обсуждаем его в главе 16.
2. Если мы хотим проверить данные, но при этом оставить их в приемном буфере для считывания какой-либо другой частью процесса, мы можем использовать флаг MSG_PEEK
(см. табл. 14.1). Если мы не уверены, что какие-либо данные готовы для чтения, мы можем объединить этот флаг с отключением блокировки для сокета или с флагом MSG_DONTWAIT
.
Помните о том, что для потокового сокета количество данных в приемном буфере может изменяться между двумя последовательными вызовами функции recv
. Например, предположим, что мы вызываем recv для сокета TCP, задавая буфер длиной 1024 и флаг MSG_PEEK
, и возвращаемое значение равно 100. Если затем мы снова вызовем функцию recv, возможно, возвратится более 100 байт (мы задаем длину буфера больше 100), поскольку в промежутке между двумя нашими вызовами recv
могли быть получены дополнительные данные.
А что произойдет в случае сокета UDP, когда в приемном буфере имеется дейтаграмма? При вызове recvfrom
с флагом MSG_PEEK
, за которым последует другой вызов без задания MSG_PEEK
, возвращаемые значения обоих вызовов (размер дейтаграммы, ее содержимое и адрес отправителя) будут совпадать, даже если в приемный буфер сокета между двумя вызовами добавляются дополнительные дейтаграммы. (Мы считаем, конечно, что никакой другой процесс не использует тот же дескриптор и не осуществляет чтение из данного сокета в это же время.)
3. Некоторые реализации поддерживают команду FIONREAD
функции ioctl
. Третий аргумент функции ioctl
— это указатель на целое число, а возвращаемое в этом целом числе значение — это текущее число байтов в приемном буфере сокета [128, с. 553]. Это значение является общим числом установленных в очередь байтов, которое для сокета UDP включает все дейтаграммы, установленные в очередь. Также помните о том, что значение, возвращаемое для сокета UDP, в Беркли-реализациях включает пространство, требуемое для структуры адреса сокета, содержащей IP-адрес отправителя и порт для каждой дейтаграммы (16 байт для IP4, 24 байта для IP6).
14.8. Сокеты и стандартный ввод-вывод
Во всех наших примерах мы применяли то, что иногда называется вводом-выводом Unix , вызывали функции read
и write
и их разновидности ( recv
, send
и т.д.). Эти функции работают с дескрипторами и обычно реализуются как системные вызовы внутри ядра Unix.
Другой метод выполнения ввода-вывода заключается в использовании стандартной библиотеки ввода-вывода . Она задается стандартом ANSI С и была задумана как библиотека, совместимая с не-Unix системами, поддерживающими ANSI С. Стандартная библиотека ввода-вывода обрабатывает некоторые моменты, о которых мы должны заботиться сами при использовании функций ввода- вывода Unix, таких как автоматическая буферизация потоков ввода и вывода. К сожалению, ее обработка буферизации потока может представить новый ряд проблем, о которых следует помнить. Глава 5 [110] подробно описывает стандартную библиотеку ввода-вывода, а в [92] представлена полная реализация стандартной библиотеки ввода-вывода и ее обсуждение.
При обсуждении стандартной библиотеки ввода-вывода используется термин «поток» в выражениях типа «мы открываем поток ввода» или «мы очищаем поток вывода». Не путайте это с подсистемой потоков STREAMS, которую мы обсуждаем в главе 31.
Стандартная библиотека ввода-вывода может использоваться с сокетами, но есть несколько моментов, которые необходимо при этом учитывать.
■ Стандартный поток ввода-вывода может быть создан из любого дескриптора при помощи вызова функции fdopen
. Аналогично, имея стандартный поток ввода-вывода, мы можем получить соответствующий дескриптор, вызывая функцию fileno
. С функцией fileno
мы впервые встретились в листинге 6.1, когда мы хотели вызвать функцию select
для стандартного потока ввода-вывода. Функция select
работает только с дескрипторами, поэтому нам необходимо было получить дескриптор для стандартного потока ввода-вывода.
■ Сокеты TCP и UDP являются двусторонними. Стандартные потоки ввода- вывода также могут быть двусторонними: мы просто открываем поток типа r+
, что означает чтение-запись. Но в таком потоке за функцией вывода не может следовать функция ввода, если между ними нет вызова функции fflush
, fseek
, fsetpots
или rewind
. Аналогично, за функцией вывода не может следовать функция ввода, если между ними нет вызова функции fseek
, fsetpots
, rewind
, в том случае, когда при вводе не получен признак конца файла. Проблема с последними тремя функциями состоит в том, что все они вызывают функцию lseek
, которая не работает с сокетами.
■ Простейший способ обработки подобной проблемы чтения-записи — это открытие двух стандартных потоков ввода-вывода для данного сокета: одного для чтения и другого для записи.
Пример: функция str_echo, использующая стандартный ввод-вывод
Сейчас мы модифицируем наш эхо-сервер TCP (см. листинг 5.2) для использования стандартного ввода-вывода вместо функций readline
и writen
. В листинге 14.6 представлена версия нашей функции str_echo
, использующая стандартный ввод-вывод. (С этой версией связана проблема, которую мы вскоре опишем.)
Интервал:
Закладка: