В настоящее время актуальный стандарт - это POSIX 2008 и его дополнение POSIX 1003.13 |
Сетевые средства
После привязки сокета к локальному адресу, а также установления, при необходимости, соединения и задания значений опций, можно приступать к отправке и/или приему данных через сокет. Для этого служат функции, описания которых показаны в листинге 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 - и то, и другое.