Это архив сайта coldflame.by.ru, он не обновлялся с 2007 года. Мой современный сайт тут: http://leonid.shevtsov.me.
Домой! Обо мне Специально для РИ-06-1 Разнообразное... барахло, короче :) Программы и прочее Статьи и переводы Блог SmartDaemon
Предыдущая ОглавлениеСледующая

recv(), recvfrom()

Получить данные из сокета

Прототипы

#include <sys/types.h>
#include <sys/socket.h>

ssize_t recv(int s, void *buf, size_t len, int flags);
ssize_t recvfrom(int s, void *buf, size_t len, int flags,
                 struct sockaddr *from, socklen_t *fromlen);

Описание

Когда у тебя есть открытый и соединенный сокет, ты можешь получать данные от удаленной стороны, используя recv() (для TCP-сокетов SOCK_STREAM) и recvfrom() (для UDP-сокетов SOCK_DGRAM).

Обе функции принимают дескриптор сокета s, указатель на буфер buf, размер буфера в байтах len и набор управляющих флагов flags.

recvfrom() также принимает структуру from, в которую будет записан адрес отправителя, и указатель на переменную fromlen, которую нужно инициализировать значением sizeof(struct sockaddr).

И что за прекрасные флаги можно передать в эти функции? Вот несколько, но тебе стоит посмотреть локальную справку, так как не все могут поддерживаться твоей системой. Собери флаги с помощью логического сложения, или просто передай 0 вместо flags, чтобы вызвать самый обычный recv().

MSG_OOB

Получить внепотоковые (Out of Band) данные data. Так можно получить данные, отосланные с флагом MSG_OOB в send(). Принимающая сторона получит сигнал SIGURG, когда поступят внепотоковые данные, и в обработчике этого сигнала нужно вызвать recv() с флагом MSG_OOB.

MSG_PEEK

Используй этот флаг, если хочешь просто узнать, сколько данных ожидают обработки. Тогда recv() сообщит объем входящих данных, а следующий вызов (без флага MSG_PEEK) их получит.

MSG_WAITALL

recv() не закончится, пока не получит объем данных, указанный в параметре len. Однако ошибка, сигнал или закрытие соединения удаленной стороной заставит функцию прерваться - даже не получив указанного объема.

recv() будет блокировать, пока не получит данные. Если ты не хочешь, чтобы она блокировала, сделай сокет неблокирующим или проверяй наличие данных с помощью select() или poll() до вызова recv() или recvfrom().

Возвращаемое значение

Возвращает число полученных байт (может, и меньше, чем число в параметре len paramter), или -1 при ошибке, сохраняя ее номер в errno.

Если удаленная сторона закрыла соединение, recv() возвращает 0. Это нормальный способ узнать, что соединение закрыто. Нормальный, значит, лучший (по крайней мере, в этом случае.)

Пример

int s1, s2;
int byte_count, fromlen;
struct sockaddr_in addr;
char buf[512];

//сначала с потоковым TCP-сокетом
s1 = socket(PF_INET, SOCK_STREAM, 0);

// данные о сервере
addr.sin_family = AF_INET;
addr.sin_port = htons(3490);
inet_aton("10.9.8.7", &addr.sin_addr);

connect(s1, &addr, sizeof(addr)); // соединяемся

// теперь сокет соединен и может получать данные 
byte_count = recv(s1, buf, sizeof(buf), 0);
printf("recv(): %d байт данных получено в buf\n", byte_count);

// теперь с датаграммным UDP-сокетом
s2 = socket(PF_INET, SOCK_DGRAM, 0);

fromlen = sizeof(addr);
byte_count = recvfrom(s2, buf, sizeof(buf), 0, &addr, &fromlen);
printf("%d байт данных получено в buf\n", byte_count);
printf("с IP-адреса %s\n", inet_ntoa(addr.sin_addr));

См. также

send(), sendto(), select(), poll(), Блокирование


Предыдущая ОглавлениеСледующая