Recv как прочесть всю страницу в си
Перейти к содержимому

Recv как прочесть всю страницу в си

  • автор:

Recv как прочесть всю страницу в си

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

ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

ОПИСАНИЕ

При успешном выполнении все три вызова возвращают длину сообщения. Если сообщение слишком длинное и не поместилось в предоставленный буфер, лишние байты могут быть отброшены, в зависимости от типа сокета, на котором принимаются сообщения.

Если на сокете не доступно ни одного сообщения, то обсуждаемые вызовы ожидают их прибытия, если сокет не помечен как неблокирующий (см. fcntl(2)), в противном случае возвращается значение -1, а внешняя переменная errno устанавливается в значение EAGAIN или EWOULDBLOCK. Все эти вызовы обычно сразу возвращают все доступные данные вплоть до запрошенного объема, а не ждут, пока появятся данные полной запрошенной длины.

Для определения появления новых данных в сокете приложение может использовать select(2), poll(2) или epoll(7).

Аргумент флагов

Ошибка передаётся в виде структуры sock_extended_err:

В ee_errno содержится значение errno для ожидающей ошибки. В ee_origin содержится источник происхождения ошибки. Смысл остальных полей зависит от протокола. Макрос SOCK_EE_OFFENDER возвращает указатель на адрес сетевого объекта, породившего ошибку. Если этот адрес неизвестен, то поле sa_family структуры sockaddr содержит значение AF_UNSPEC, а прочие поля структуры sockaddr не определены. Содержимое пакета, вызвавшего ошибку, передаётся в виде обычных данных. Для локальных ошибок адрес не передаётся (это можно выяснить, проверив поле cmsg_len структуры cmsghdr). Для ошибок при приёме устанавливается флаг MSG_ERRQUEUE в msghdr. После того, как ошибка передана программе, следующая ошибка в очереди ошибок становится ожидающей ошибкой и передается программе при следующей операции на сокете. MSG_OOB Этот флаг запрашивает приём внеполосных данных, которые в противном случае не были бы получены в обычном потоке данных. Некоторые протоколы помещают данные повышенной срочности в начало очереди с обычными данными, и поэтому этот флаг не может использоваться с такими протоколами. MSG_PEEK Этот флаг заставляет выбрать данные из начала очереди приёма, но не удалять их оттуда. Таким образом, последующий вызов вернёт те же самые данные. MSG_TRUNC (начиная с Linux 2.2) Для «сырых» данных (AF_PACKET), дейтаграмм Интернета (начиная с Linux 2.4.27/2.6.8), netlink (начиная с Linux 2.6.22) и дейтаграмм UNIX (начиная с Linux 3.4) возвращает реальную длину пакета или дейтаграммы, даже если она была больше, чем предоставленный буфер.

Описание использования с потоковым сокетами Интернета смотрите в tcp(7).

MSG_WAITALL (начиная с Linux 2.2) Этим флагом включается блокирование операции до полной обработки запроса. Однако, этот вызов всё равно может вернуть меньше данных, чем было запрошено, если был пойман сигнал, произошла ошибка или разрыв соединения, или если начали поступать данные другого типа, не того, который был сначала.

recvfrom()

Если значение src_addr не равно NULL, и в нижележащем протоколе используется адрес источника сообщения, то адрес источника помещается в буфер, указанный в src_addr. В этом случае addrlen является аргументом-результатом. Перед вызовом ему должно быть присвоено значение длины буфера, связанного с src_addr. При возврате addrlen обновляется и содержит действительный размер адреса источника. Возвращаемый адрес обрезается, если предоставленный буфер слишком мал; в этом случае addrlen будет содержать значение большее, чем указывалось в вызове.

Если вызывающему адрес источника не нужен, то значение src_addr и addrlen должно быть равно NULL.

recvfrom(fd, buf, len, flags, NULL, 0));

recvmsg()

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

В полях msg_iov и msg_iovlen описываются место приёма/передачи, обсуждаемые в readv(2).

Поле msg_control длиной msg_controllen указывает на буфер для других сообщений, связанных с управлением протоколом или на буфер для разнообразных вспомогательных данных. При вызове recvmsg() в поле msg_controllen должен указываться размер доступного буфера, чей адрес передан в msg_control; при успешном выполнении вызова в этом параметре будет находиться длина последовательности контрольных сообщений.

Сообщения имеют следующий вид:

К вспомогательным данным нужно обращаться только с помощью макросов, определённых в cmsg(3).

Например, этот механизм вспомогательных данных используется в Linux для передачи расширенных ошибок, флагов IP и файловых дескрипторов через доменные сокеты Unix.

При возврате из recvmsg() устанавливается значение поля msg_flags в msghdr. Оно может содержать несколько флагов:

MSG_EOR означает конец записи: возвращённые данные заканчивают запись (обычно используется вместе с сокетами типа SOCK_SEQPACKET). MSG_TRUNC означает, что хвостовая часть датаграммы была отброшена, потому что датаграмма была больше, чем предоставленный буфер. MSG_CTRUNC означает, что часть управляющих данных была отброшена из-за недостатка места в буфере вспомогательных данных. MSG_OOB возвращается для индикации получения внеполосных данных. MSG_ERRQUEUE означает, что были получены не данные, а расширенное сообщение об ошибке из очереди ошибок сокета.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

Когда ответная сторона потока выполняет корректное отключение (shutdown), то возвращается 0 (обычный возврат «конец файла»).

В датаграмных сокетах некоторых доменов (например, доменах UNIX и Internet) разрешены датаграммы нулевой длины. При получении такой датаграммы возвращается значение 0.

Также значение 0 может возвращаться, если запрошенное количество принимаемых байт из потокового сокета равно 0.

ОШИБКИ

СООТВЕТСТВИЕ СТАНДАРТАМ

В POSIX.1 описаны только флаги MSG_OOB, MSG_PEEK и MSG_WAITALL.

ЗАМЕЧАНИЯ

В соответствие с POSIX.1 поле msg_controllen структуры msghdr должно иметь тип socklen_t, но в настоящее время в glibc оно имеет тип size_t.

В recvmmsg(2) можно найти информацию о специальном системном вызове Linux, который можно использовать для приёма нескольких датаграмм за один вызов.

How to Receive Full Data with recv() Socket function in C on Linux – Code Example

If you are writing a network application using sockets in C that communicates with a remote server and fetches data, then you must be aware of the recv function that is used to receive data.

The recv function can only receive a specified number of bytes in the response. If the response has less content than the specified byte size then its okay.

But if the response is larger than the specified number of bytes then only the initial chunk is received and the rest is lost.

This is the typical problem with the recv function. Lets take a look at an example to understand what is happening.

Code example

The recv function is used to receive data on a socket.
For example here is the code to fetch the home page of www.msn.com

The output might be something like this

The problem with the output is that it is incomplete. We already used a large sized buffer of 6000 characters to receive the reply.

There cause of this problem is that we do not know the exact size of the response beforehand.

We might try to do any of these :

1. Use a very large buffer — But all data does not come in at once. The response comes as several TCP packets. So the recv function would return after receiving even partial data.

2. Making recv function wait till full size is received — But we do not know the full size.

Receive in multiple chunks — The Solution

A simple solution might look like this

If the CHUNK_SIZE is relatively small compared to the total size of the response then it will work but partially.
Lets say the CHUNK_SIZE = 512 and data is much larger. Then the recv function would receive data in a fashion similar to this

The last call would be returning an amount of data that is smaller than the chunk size (unless the whole response size is a multiple of the CHUNK_SIZE).

Now in the last call to recv, it would block till it gets CHUNK_SIZE amount of data or a default timeout occurs which can be from 30 seconds to 1 minute. This can be too much of waiting for an application.

An alternative strategy would be to receive without waiting and with a specific maximum timeout. Here are the steps .

1. Try to receive some data, lets say 512 bytes. If nothing is received till a certain timeout then stop.
2. Go to step 1.

Final Code

The recv_timeout function receives data on a socket with a given maximum timeout. The above program should fetch the full html content of www.msn.com till the closing html tag.

Data is received in chunks of size 512 bytes. This can be set to a different value like 1024 or 2000 or anything.

Another important change is that the socket is set in non blocking mode. When the socket is in non-blocking mode, then recv would not block and return immediately. If data is there it would return with the data otherwise with an error.

In the above example the socket can be kept blocking. Then the recv function must use the flag MSG_DONTWAIT

Both techniques should produce identical results.

Conclusion

This technique of waiting for some timeout may not be the most efficient or reliable technique to ensure that full data has been received.

The most reliable approach would be to have some sort of indicator that confirms completion of transfer.

The reply can for example have and «end marker» or the total response size mentioned in it somewhere so that the receiving application can judge it better.

If you have any feedback or questions, let us know in the comments below.

A Tech Enthusiast, Blogger, Linux Fan and a Software Developer. Writes about Computer hardware, Linux and Open Source software and coding in Python, Php and Javascript. He can be reached at [email protected] .

19 Comments

Hi ,
Thanks for wonderful tutorial , still trying to grasp it :).
Just one doubt , what about server side?
When we have to send large ammount of data from server , we need to call send() multiple time in loop as we calling recv() from client.?

Thanks for a very useful article. I tried your code and found that a modified receive_basic() code can do away with the recv_timeout(int s , int timeout) function. Instead of making the socket nonblocking with fcntl(), one can use setsockopt() to set a desired timeout value in receive_basic(). For example, the below receive_basic(int s_fd) would wait for 1.5 seconds to time out and be able to receive all the data — Received 48046 bytes from google.com.

#define CHUNK_SIZE 2048
#define TO_SEC 1
#define TO_USEC 50000

int receive_basic(int s_fd) // Block on recv
<
int rcvBytes, loopRcvd = 0, totalRcvd = 0;
char chunk[CHUNK_SIZE];

struct timeval tv = ;
setsockopt(s_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
while(1)
<
memset(chunk, 0, CHUNK_SIZE);
if ((rcvBytes = recv(s_fd, chunk, sizeof(chunk), 0)) >\n%s\n”, rcvBytes, loopRcvd, chunk);
>
>

printf(“Exiting receive_basic(s_fd %d) with loopRcvd %d\n\n”, s_fd, loopRcvd);
return totalRcvd;
>

One should set the timeout value at least longer than the expected arrival time of the first chunk message, else the loop may break prematurely with 0 received bytes.

It worked for me…very nice program…

put the recv system call in a loop instead of if statement (repeat until it returns 0). it’ll then receive the full data. to end the connection, simply add the following header to your http message:
Connection: close

Genius idea. Trying this after work.

Does this assume that the remote server closes the socket as soon as it’s finished sending the message? As I understand, recv() only returns 0 if the socket has been closed. So this method wouldn’t work if you want to keep the connection open for a reply, right?

Can you say something with get format?

If you get error messages with this code on your Linux machine, look for the following problems.

1. Don’t forget to “#include ” for the gettimeofday() function.
2. Get rid of the declaration for “server_reply[2000]” because it is unused and will generate a warning.

Very good article for someone (like me) who is just now learning about sockets in C. Thanks very much for posting this article! I’ve been going nuts trying to figure out how to do this. 🙂

Is there any way to request an end marker or total response size from the server or would this have to be coded into the server-side program?

There is no direct way of fetching the total response size. It has to be coded in the server and client program.

1. For example 2 consecutive newlines can indicate the end of data. So this logic has to be coded in both the server and the client. The server appends 2 newlines to the total response, and the client upon detecting such a pattern closes the connection and marks transfer complete for the application.

2. Another way is to send the total size before sending the actual response. For example server sends like this

So first the total size is mentioned and then after 2 newlines the actual response follows, so the client has to deal with this, either wait till 1024 bytes of data in the response part is received. For example http response send by http servers has a “content-length” value in its header which tells the total size of the response.

Both the techniques can be developed further to ensure reliable transfer of full data.

Still playing around with your code, making changes to see how things work and what I can do with it. Playing around with headers and portions of the code to get a better feel for how it works.

Thanks again for sharing your knowledge!

year but this is not at tutorial in how to recive a known data size.

what if you want to recive from a external server, that dosent send the size of the packet?

if the server does not send the size of the packet, then the program has to decide this itself whether the transfer has completed or not.
For example if the socket connection closes or no data received for a large timeout.

Simply put, its not possible to know if the transfer completed successfully or not.

Hello!
This is a very common misconception about tcp. tcp is a stream of bytes. You MUST have a protocol inside
our stream ala header, message, endofdata. You must linger and wait for this complete packet and THEN
return. If your server is slow you can have an alarm(1) to end the listening. But you MUST have a progocol to adhere to.
// GH

yes, any real world application should certainly use a dedicated application protocol with its own header and integrity checks.
the article above is to just show a basic example of how to use sockets in general.

thanks .. It is exactly for me…

Can we do an HTTPS( port 443) in same way?

HTTPS might not work since you are expected to have a valid certificate or credentials. You can try working with an authenticity manager..

Recv как прочесть всю страницу в си

Когда возвращаемое значение <0 и (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN), соединение считается нормальным и прием продолжается.

EAGAIN, EWOULDBLOCK, EINTR и неблокирование
  • EWOULDBLOCK : Для неблокирующего режима нет необходимости читать или писать снова
  • EINTR : Указывает на то, что операция была вызвана прерыванием и должна быть снова прочитана / записана.

Если происходит EINTR, то есть значение errno равно 4, ошибка описывает прерванный системный вызов, и операция должна продолжаться.

  • EAGAIN : Linux-неблокирующее программирование сокетов обрабатывает ошибки EAGAIN

Ресурс, временно недоступный, часто возникает при получении данных в неблокирующем сокете в Linux, а код ошибки равен 11 (EAGAIN). Буквально, это подсказка, чтобы попробовать еще раз. Эта ошибка часто возникает, когда приложение выполняет некоторые неблокирующие операции (над файлами или сокетами). Эта ошибка не нарушит синхронизацию сокета, независимо от этого, следующий цикл может быть восстановлен.

Для неблокирующих сокетов EAGAIN не является ошибкой. В VxWorks и Windows имя EAGAIN — EWOULDBLOCK.

Например, откройте файл / socket / FIFO с флагом O_NONBLOCK, если вы выполняете операции чтения непрерывно и данные не могут быть прочитаны. На этом этапе программа не будет блокироваться, пока данные не будут готовы к возврату. Функция чтения вернет ошибку EAGAIN, указывающую, что у вашего приложения нет данных для чтения. Повторите попытку позже.

В другом примере, когда системный вызов (такой как fork) не выполняется из-за нехватки ресурсов (например, виртуальной памяти), верните EAGAIN, чтобы запросить повторный вызов (возможно, в следующий раз это произойдет).

Recv как прочесть всю страницу в си

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

ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

ОПИСАНИЕ

При успешном выполнении все три вызова возвращают длину сообщения. Если сообщение слишком длинное и не поместилось в предоставленный буфер, лишние байты могут быть отброшены, в зависимости от типа сокета, на котором принимаются сообщения.

Если на сокете не доступно ни одного сообщения, то обсуждаемые вызовы ожидают их прибытия, если сокет не помечен как неблокирующий (см. fcntl(2)), в противном случае возвращается значение -1, а внешняя переменная errno устанавливается в значение EAGAIN или EWOULDBLOCK. Все эти вызовы обычно сразу возвращают все доступные данные вплоть до запрошенного объема, а не ждут, пока появятся данные полной запрошенной длины.

Для определения появления новых данных в сокете приложение может использовать select(2), poll(2) или epoll(7).

Аргумент флагов

Ошибка передаётся в виде структуры sock_extended_err:

В ee_errno содержится значение errno для ожидающей ошибки. В ee_origin содержится источник происхождения ошибки. Смысл остальных полей зависит от протокола. Макрос SOCK_EE_OFFENDER возвращает указатель на адрес сетевого объекта, породившего ошибку. Если этот адрес неизвестен, то поле sa_family структуры sockaddr содержит значение AF_UNSPEC, а прочие поля структуры sockaddr не определены. Содержимое пакета, вызвавшего ошибку, передаётся в виде обычных данных. Для локальных ошибок адрес не передаётся (это можно выяснить, проверив поле cmsg_len структуры cmsghdr). Для ошибок при приёме устанавливается флаг MSG_ERRQUEUE в msghdr. После того, как ошибка передана программе, следующая ошибка в очереди ошибок становится ожидающей ошибкой и передается программе при следующей операции на сокете. MSG_OOB Этот флаг запрашивает приём внеполосных данных, которые в противном случае не были бы получены в обычном потоке данных. Некоторые протоколы помещают данные повышенной срочности в начало очереди с обычными данными, и поэтому этот флаг не может использоваться с такими протоколами. MSG_PEEK Этот флаг заставляет выбрать данные из начала очереди приёма, но не удалять их оттуда. Таким образом, последующий вызов вернёт те же самые данные. MSG_TRUNC (начиная с Linux 2.2) Для «сырых» данных (AF_PACKET), дейтаграмм Интернета (начиная с Linux 2.4.27/2.6.8), netlink (начиная с Linux 2.6.22) и дейтаграмм UNIX (начиная с Linux 3.4) возвращает реальную длину пакета или дейтаграммы, даже если она была больше, чем предоставленный буфер.

Описание использования с потоковым сокетами Интернета смотрите в tcp(7).

MSG_WAITALL (начиная с Linux 2.2) Этим флагом включается блокирование операции до полной обработки запроса. Однако, этот вызов всё равно может вернуть меньше данных, чем было запрошено, если был пойман сигнал, произошла ошибка или разрыв соединения, или если начали поступать данные другого типа, не того, который был сначала.

recvfrom()

Если значение src_addr не равно NULL, и в нижележащем протоколе используется адрес источника сообщения, то адрес источника помещается в буфер, указанный в src_addr. В этом случае addrlen является аргументом-результатом. Перед вызовом ему должно быть присвоено значение длины буфера, связанного с src_addr. При возврате addrlen обновляется и содержит действительный размер адреса источника. Возвращаемый адрес обрезается, если предоставленный буфер слишком мал; в этом случае addrlen будет содержать значение большее, чем указывалось в вызове.

Если вызывающему адрес источника не нужен, то значение src_addr и addrlen должно быть равно NULL.

recvfrom(fd, buf, len, flags, NULL, 0));

recvmsg()

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

В полях msg_iov и msg_iovlen описываются место приёма/передачи, обсуждаемые в readv(2).

Поле msg_control длиной msg_controllen указывает на буфер для других сообщений, связанных с управлением протоколом или на буфер для разнообразных вспомогательных данных. При вызове recvmsg() в поле msg_controllen должен указываться размер доступного буфера, чей адрес передан в msg_control; при успешном выполнении вызова в этом параметре будет находиться длина последовательности контрольных сообщений.

Сообщения имеют следующий вид:

К вспомогательным данным нужно обращаться только с помощью макросов, определённых в cmsg(3).

Например, этот механизм вспомогательных данных используется в Linux для передачи расширенных ошибок, флагов IP и файловых дескрипторов через доменные сокеты Unix.

При возврате из recvmsg() устанавливается значение поля msg_flags в msghdr. Оно может содержать несколько флагов:

MSG_EOR означает конец записи: возвращённые данные заканчивают запись (обычно используется вместе с сокетами типа SOCK_SEQPACKET). MSG_TRUNC означает, что хвостовая часть датаграммы была отброшена, потому что датаграмма была больше, чем предоставленный буфер. MSG_CTRUNC означает, что часть управляющих данных была отброшена из-за недостатка места в буфере вспомогательных данных. MSG_OOB возвращается для индикации получения внеполосных данных. MSG_ERRQUEUE означает, что были получены не данные, а расширенное сообщение об ошибке из очереди ошибок сокета.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

Когда ответная сторона потока выполняет корректное отключение (shutdown), то возвращается 0 (обычный возврат «конец файла»).

В датаграмных сокетах некоторых доменов (например, доменах UNIX и Internet) разрешены датаграммы нулевой длины. При получении такой датаграммы возвращается значение 0.

Также значение 0 может возвращаться, если запрошенное количество принимаемых байт из потокового сокета равно 0.

ОШИБКИ

СООТВЕТСТВИЕ СТАНДАРТАМ

В POSIX.1 описаны только флаги MSG_OOB, MSG_PEEK и MSG_WAITALL.

ЗАМЕЧАНИЯ

В соответствие с POSIX.1 поле msg_controllen структуры msghdr должно иметь тип socklen_t, но в настоящее время в glibc оно имеет тип size_t.

В recvmmsg(2) можно найти информацию о специальном системном вызове Linux, который можно использовать для приёма нескольких датаграмм за один вызов.

Получить html код страницы с использованием сокетов

Если в адрес ввожу ya.ru, то ждем две минуты пока консоль пустая, а затем выдает ошибку 10060
Если вводить как-либо другой адрес, то сразу же выдает ошибку 10049
Что я делаю не так, подскажите?

Добавлено через 11 часов 58 минут
Рабочий код:

Получить код html-страницы
Нужно через C++ получить код html-страницы по http/https.

Получить размер страницы html
Привет всем. Нужно скачать страницу, например, cyberforum.ru. Для этого мне нужно сначала узнать.

Получить html код
Подскажите, как получить html код странице? Пишу в консольке, в Dev-C++

Написать сервер с использованием сокетов
Ребята, нужно написать сервер за неделю на си++ с использованием сокетов, а я в этом вообще не.

.
И еще один вопрос: Я так понимаю, многие люди просматривающие эту тему вообще не пробовали работать с сокетами, мне интересно, вы зарабатываете фрилансом программируя на C++?

Добавлено через 1 час 19 минут
Это страница скоро станет моим дневником.
Ссылка на W3C HTTP 1.1 https://www.w3.org/Protocols/rfc2616/rfc2616.html

Сообщение от supvlmail
Сообщение от supvlmail
Сообщение от supvlmail

Добавлено через 10 минут
PS. supvlmail,
уважаемый vxg выше дал вам ссылку на рабочий пример с правильным запросом. Вы и её не просмотрели.

Добавлено через 15 минут

Сообщение от supvlmail

Начну с того, что я подавлен вашим ответом. Зачем так грубо да еще и мимо?
Код не работает. Yandx выдает 400 Bad Request.
Статью я открывал, но сразу же закрыл, так как там используется gethostbyname.
Сертификат от клиента вообще может не передаваться, по http высылается открытый ключ, ты его по https если вышлешь, у тебя как клиент его расшифрует? — Поэтому как писал выше, первый ответ должен быть http.
PS После строки инициализации "GET /index.html HTTP/1.1" вообще больше запросов можно не посылать, сервер поставит стандартные значения.
PS2 Спасибо за репутацию, гений

Добавлено через 13 минут
Объясните мне пожалуйста, зачем дублировать Host, если он указан в getaddrinfo?

Лучший ответСообщение было отмечено supvlmail как решение

Recv как прочесть всю страницу в си

int recv(int s , void * buf , size_t len , int flags );

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

int recvmsg(int s , struct msghdr * msg , int flags );

ОПИСАНИЕ

Если параметр from не равен NULL , а сокет не является ориентированным на соединения, то адрес отправителя в сообщении не заполняется. Аргумент fromlen передается по ссылке, в начале инициализируется размером буфера, связанного с from , а при возврате из функции содержит действительный размер адреса.

Вызов recv обычно используется только на соединенном сокете (см. connect (2)) и идентичен вызову recvfrom с параметром from , установленным в NULL .

Все три функции возвращают длину сообщения при успешном завершении. Если сообщение слишком длинное и не поместилось в предоставленный буфер, лишние байты могут быть отброшены, в зависимости от типа сокета, на котором принимаются сообщения (см. socket (2)).

Если на сокете не доступно ни одного сообщения, то обсуждаемые функции ожидают их прибытия, если сокет не помечен как неблокирующий (см. fcntl (2)), в противном случае возвращается значение -1, а внешняя переменная errno устанавливается в значение EAGAIN . Все эти функции обычно возвращают уже доступные данные вплоть до запрошенного объема, и не ждут, пока появятся данные полной запрошенной длины.

Системные вызовы select (2) или poll (2) можно использовать для определения появления новых данных.

Аргумент flags системного вызова recv формируется с помощью объединения логической операцией ИЛИ одного или более нижеследующих значений: MSG_OOB Этот флаг запрашивает прием внепотоковых данных, которые в противном случае не были бы получены в обычном потоке данных. Некоторые протоколы помещают данные повышенной срочности в начало обычной очереди данных, и поэтому этот флаг не может использоваться с такими протоколами. MSG_PEEK Этот флаг заставляет выбрать данные из начала очереди, но не удалять их оттуда. Таким образом, последующий вызов функции вернет те же самые данные. MSG_WAITALL Этот флаг просит подождать, пока не придет полное запрошенное количество данных. Однако, этот вызов все равно может вернуть меньше данных, чем было запрошено, если был пойман сигнал, произошла ошибка или разрыв соединения, или если начали поступать данные другого типа, не того, который был сначала. MSG_TRUNC Возвращает реальную длину пакета, даже если она была больше, чем предоставленный буфер. Этот флаг можно использовать только с пакетными протоколами. MSG_ERRQUEUE Получить пакет из очереди ошибок. MSG_NOSIGNAL Этот флаг отключает возникновение сигнала SIGPIPE на потоковых сокетах, если другая сторона вдруг исчезает. MSG_ERRQUEUE Указание этого флага позволяет получить из очереди ошибок сокета накопившиеся ошибки. Каждая ошибка передается во вспомогательном сообщении, чей тип зависит от протокола (для IPv4 этим типом является IP_RECVERR ). Пользователь должен предоставить буфер достаточной длины. См. cmsg (3) и ip (7), где приведена дополнительная информация. Содержимое исходного пакета, который привел к ошибке, передается в виде обычных данных с помощью msg_iovec . Исходный адрес назначения датаграммы, которая вызвала ошибку, передается с помощью msg_name . Для локальных ошибок адрес не передается (это можно выяснить, проверив поле cmsg_len структуры cmsghdr ). Для ошибок при приеме в msghdr устанавливается MSG_ERRQUEUE . После того, как ошибка передана программе, следующая ошибка в очереди ошибок становится ожидающей ошибкой и передается программе при следующей операции на сокете.

Ошибка хранится в структуре sock_extended_err : ee_errno содержит значение errno для ожидающей ошибки. ee_origin источник происхождения ошибки. Смысл остальных полей зависит от протокола. SOCK_EE_OFFENDER возвращает указатель на адрес сетевого объекта, породившего ошибку. Если этот адрес неизвестен, то член sa_family структуры sockaddr содержит значение AF_UNSPEC , а прочие поля структуры не определены. Содержимое пакета, вызвавшего ошибку, передаются в виде обычных данных. Для локальных ошибок адрес не передается (это можно проверить, взглянув на член cmsg_len структуры cmsghdr ). При приеме ошибок в структуре msghdr установлен флаг MSG_ERRQUEUE . После того, как ошибка была передана, следующая в очереди ошибка используется для перегенерации ошибки сокета, и именно она будет возвращена при следующей операции с этим сокетом.

Системный вызов recvmsg использует структуру msghdr для того, чтобы минимизировать количество непосредственно передаваемых параметров. Эта структура определена в <sys/socket.h> так:

Здесь msg_name и msg_namelen задают адрес назначения, если сокет не соединен; в параметре msg_name можно передать NULL , если имена не требуются или вообще нежелательны. Поля msg_iov и msg_iovlen описывают точки scatter-gather, что обсуждается в readv (2). Поле msg_control , имеющее длину msg_controllen , указывает на буфер для других сообщений, связанных с управлением протоколов, или на буфер для разнообразных вспомогательных данных. Когда вызывается recvmsg , в параметре msg_controllen должна находиться длина доступного буфера, чей адрес передается в msg_control ; при успешном завершении в этом параметре будет находиться длина последовательности контрольных сообщений.

Сообщения имеют такую форму:

К вспомогательным данным нужно обращаться только с помощью макросов, определенных в cmsg (3).

Например, Linux использует этот механизм вспомогательных данных для того, чтобы передавать через Unix-сокеты расширенные ошибки, флаги IP и файловые дескрипторы.

Поле msg_flags в msghdr устанавливается при возврате из recvmsg (2). Оно может содержать несколько флагов: MSG_EOR означает "конец записи": возвращенные данные заканчивают запись (обычно используется вместе с сокетами типа SOCK_SEQPACKET ). MSG_TRUNC означает, что хвостовая часть датаграммы была отброшена, потому что датаграмма была больше, чем предоставленный буфер. MSG_CTRUNC означает, что часть управляющих данных была отброшена из-за недостатка места в буфере вспомогательных данных. MSG_OOB возвращается для индикации получения внепотоковых данных. MSG_ERRQUEUE означает, что были получены не данные, а расширенное сообщение об ошибке из очереди ошибок сокета. MSG_DONTWAIT Разрешает неблокирующий режим. Если операция могла бы привести к блокировке, возвращается EAGAIN (этот режим можно также включить с помощью O_NONBLOCK и функции F_SETFL системного вызова fcntl (2)).

Recv как прочесть всю страницу в си

The recv function is declared in the header file sys/socket.h . If your flags argument is zero, you can just as well use read instead of recv ; see Input and Output Primitives.

Function: ssize_t recv (int socket , void * buffer , size_t size , int flags )

Preliminary: | MT-Safe | AS-Safe | AC-Safe | See POSIX Safety Concepts.

The recv function is like read , but with the additional flags flags . The possible values of flags are described in Socket Data Options.

If nonblocking mode is set for socket , and no data are available to be read, recv fails immediately rather than waiting. See File Status Flags, for information about nonblocking mode.

This function returns the number of bytes received, or -1 on failure. The following errno error conditions are defined for this function:

The socket argument is not a valid file descriptor.

The descriptor socket is not a socket.

Nonblocking mode has been set on the socket, and the read operation would block. (Normally, recv blocks until there is input available to be read.)

The operation was interrupted by a signal before any data was read. See Primitives Interrupted by Signals.

You never connected this socket.

This function is defined as a cancellation point in multi-threaded programs, so one has to be prepared for this and make sure that allocated resources (like memory, file descriptors, semaphores or whatever) are freed even if the thread is canceled.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *