Получить данные из сокета
- Прототипы
-
#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(),
Блокирование
|