Опубликован: 15.06.2004 | Доступ: свободный | Студентов: 2557 / 712 | Оценка: 4.35 / 3.96 | Длительность: 27:47:00
ISBN: 978-5-9556-0011-6
Лекция 11:

Сетевые средства

После привязки сокета к локальному адресу, а также установления, при необходимости, соединения и задания значений опций, можно приступать к отправке и/или приему данных через сокет. Для этого служат функции, описания которых показаны в листинге 11.28.

#include <sys/socket.h>
ssize_t recvfrom 
        (int sd, void *restrict buffer, 
         size_t length, int flags, 
         struct sockaddr *restrict address, 
         socklen_t *restrict address_len);
ssize_t recv (int sd, void *buffer, 
              size_t length, int flags);  
ssize_t recvmsg (int sd, struct msghdr 
                 *message, int flags);
ssize_t sendto 
        (int sd, const void *message,
         size_t length, int flags, 
         const struct sockaddr *dest_addr, 
         socklen_t dest_len);
ssize_t send (int sd, const void *buffer,
              size_t length, int flags);
ssize_t sendmsg (int sd, const struct msghdr
                 *message, int flags);
Листинг 11.28. Описание функций обмена данными через сокет.

Функция recvfrom() позволяет прочитать данные (в рассматриваемом контексте называемые также сообщением ) из сокета с дескриптором sd и поместить их в буфер buffer длины length. Обычно функцию recvfrom() применяют к сокетам, ориентированным на режим без установления соединения, поскольку она выдает исходный адрес в структуре типа sockaddr.

В число возможных составляющих значения аргумента flags входят следующие флаги.

MSG_PEEK

Не удалять прочитанные данные. Следующий вызов recvfrom() или другой функции ввода снова вернет их.

MSG_WAITALL

Для сокетов типа SOCK_STREAM флаг означает, что вызывающий процесс блокируется до получения всего запрошенного объема данных (а не до прихода первого сообщения ).

MSG_OOB

Запрашиваются экстренные данные. Трактовка этого понятия зависит от протокола.

Как и положено функции ввода, в результате recvfrom() возвращает количество прочитанных и помещенных в буфер данных. Для сокетов, учитывающих границы сообщений ( SOCK_RAW, SOCK_DGRAM, SOCK_SEQPACKET ), за одно обращение читается все сообщение ; если оно не помещается в буфер, лишние байты (в отсутствие флага MSG_PEEK ) отбрасываются.

Формально можно считать, что функция recv() эквивалентна recvfrom() с нулевым значением аргумента address_len. Поскольку она не позволяет узнать исходный адрес, ее обычно используют для сокетов, установивших соединение. (Можно провести и еще одну аналогию: если пренебречь флагами, функция recv() эквивалентна read().)

По сравнению с recv(), более содержательным аналогом функции recvfrom() является recvmsg(). Отличия в данном случае носят скорее синтаксический характер и по сути сводятся к способу передачи входных значений и возврата результатов: для минимизации числа аргументов функция recvmsg() использует структуру типа msghdr, которая, согласно стандарту POSIX-2001, должна содержать по крайней мере следующие поля.

void         *msg_name;         
/* Указатель на буфер для адреса            */
/* (исходного или целевого)                 */

socklen_t     msg_namelen;      
/* Размер буфера для адреса                 */

struct iovec *msg_iov;          
/* Массив для разнесения/сборки сообщений   */

int           msg_iovlen;       
/* Число элементов в массиве                */
/* для разнесения/сборки сообщений          */

void         *msg_control;      
/* Указатель на буфер                       */
/* для вспомогательных данных               */

socklen_t     msg_controllen;   
/* Размер буфера для вспомогательных данных */  

int           msg_flags;        
/* Флаги принятого сообщения                */

Если для сокета, специфицированного дескриптором sd, соединение не установлено, в заданный указателем msg_name буфер длины msg_namelen помещается исходный адрес сообщения ; если этого не нужно, указатель msg_name можно сделать пустым. При установлении соединения оба поля игнорируются.

Массив msg_iov совместно с полем msg_iovlen задает набор буферов для размещения принимаемых данных. Структура типа iovec определяется в заголовочном файле <sys/uio.h> и содержит по крайней мере два поля.

void  *iov_base;        
/* Адрес области памяти (буфера)    */

size_t iov_len;         
/* Размер области памяти (в байтах) */

Заданные полем msg_iov области памяти по очереди заполняются поступающими данными, пока не будут размещены все принятые данные или не заполнятся все буфера.

Трактовка вспомогательных данных (поля msg_control и msg_controllen структуры типа msghdr ) в стандарте POSIX-2001 весьма туманна. Описаны лишь средства доступа к ним. Мы, однако, не будем на этом останавливаться.

В случае успешного завершения функции recvmsg() в поле msg_flags могут быть установлены следующие флаги.

MSG_EOR

Достигнута граница записи (если это понятие поддерживается протоколом ).

MSG_OOB

Получены экстренные данные.

MSG_TRUNC

Пришлось урезать обычные данные.

MSG_CTRUNC

Пришлось урезать управляющие данные.

Подобно тому, как write() составляет пару read(), функцию sendto() можно считать парной по отношению к recvfrom(). Она предназначена для отправки через сокет sd сообщения, заданного аргументами message и length, по адресу dest_addr длины dest_len. Если для сокета установлено соединение, целевой адрес dest_addr игнорируется.

В число возможных составляющих значения аргумента flags входят следующие флаги.

MSG_EOR

Обозначает границу записи (если это понятие поддерживается протоколом ).

MSG_OOB

Отправляются экстренные данные.

Разумеется, успешное завершение функции sendto() не гарантирует доставку сообщения. Результат, равный -1, указывает только на локально выявляемые ошибки.

Функция send() - пара для recv() со всеми следующими из этого обстоятельства эквивалентностями и аналогиями.

Для функции sendmsg() структура типа msghdr, на которую указывает аргумент message, является входной (что показывает спецификатор const ). В поле msg_name задается целевой адрес. Поле msg_flags игнорируется.

Для завершения операций приема и/или отправки данных через сокет служит функция shutdown() (см. листинг 11.29).

#include <sys/socket.h>
int shutdown (int sd, int how);
Листинг 11.29. Описание функции shutdown().

Значение аргумента how показывает, что именно завершается: SHUT_RD прекращает прием, SHUT_WR - отправку, SHUT_RDWR - и то, и другое.

Антон Коновалов
Антон Коновалов

В настоящее время актуальный стандарт - это POSIX 2008 и его дополнение POSIX 1003.13
Планируется ли актуализация материалов данного очень полезного курса?