Функция WSARecvFrom (winsock2.h)

Функция WSARecvFrom получает датаграмму и сохраняет исходный адрес.

Синтаксис

int WSAAPI WSARecvFrom(
  [in]      SOCKET                             s,
  [in, out] LPWSABUF                           lpBuffers,
  [in]      DWORD                              dwBufferCount,
  [out]     LPDWORD                            lpNumberOfBytesRecvd,
  [in, out] LPDWORD                            lpFlags,
  [out]     sockaddr                           *lpFrom,
  [in, out] LPINT                              lpFromlen,
  [in]      LPWSAOVERLAPPED                    lpOverlapped,
  [in]      LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);

Параметры

[in] s

Дескриптор, определяющий сокет.

[in, out] lpBuffers

Указатель на массив структур WSABUF . Каждая структура WSABUF содержит указатель на буфер и его длину.

[in] dwBufferCount

Количество структур WSABUF в массиве lpBuffers .

[out] lpNumberOfBytesRecvd

Указатель на количество байтов, полученных этим вызовом, если операция WSARecvFrom завершается немедленно.

Используйте значение NULL для этого параметра, если параметр lpOverlapped не имеет значения NULL , чтобы избежать потенциально ошибочных результатов. Этот параметр может иметь значение NULL , только если параметр lpOverlapped не равен NULL.

[in, out] lpFlags

Указатель на флаги, используемые для изменения поведения вызова функции WSARecvFrom . См. примечания ниже.

[out] lpFrom

Необязательный указатель на буфер, который будет содержать исходный адрес после завершения перекрывающейся операции.

[in, out] lpFromlen

Указатель на размер (в байтах) буфера "from" требуется только в том случае, если указан параметр lpFrom .

[in] lpOverlapped

Указатель на структуру WSAOVERLAPPED (игнорируется для непереключенных сокетов).

[in] lpCompletionRoutine

Тип: _In_opt_ LPWSAOVERLAPPED_COMPLETION_ROUTINE

Указатель на подпрограмму завершения, вызываемую при завершении операции WSARecvFrom (игнорируется для неперекрывающихся сокетов).

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

Если ошибка не возникает и операция получения завершена немедленно, WSARecvFrom возвращает ноль. В этом случае подпрограмма завершения будет уже запланирована для вызова, когда вызывающий поток перейдет в состояние предупреждения. В противном случае возвращается значение SOCKET_ERROR , а определенный код ошибки можно получить, вызвав WSAGetLastError. Код ошибки WSA_IO_PENDING указывает, что перекрывающаяся операция успешно запущена и что завершение будет указано позже. Любой другой код ошибки указывает на то, что перекрывающаяся операция не была успешно инициирована и не будет показаний завершения.

Код ошибки Значение
WSAECONNRESET
Виртуальное подключение было сброшено удаленной стороной путем прерывания. Приложение должно закрыть сокет, поскольку он больше не может использоваться. Для сокета датаграмм UPD эта ошибка указывает на то, что предыдущая операция отправки привела к сообщению ICMP "Порт недоступен".
WSAEFAULT
Параметр lpBuffers, lpFlags, lpFrom, lpNumberOfBytesRecvd, lpFromlen, lpOverlapped или lpCompletionRoutine не полностью содержится в допустимой части адресного пространства пользователя: буфер lpFrom был слишком мал для размещения однорангового адреса.
WSAEINPROGRESS
Выполняется блокирующий вызов Windows Sockets 1.1 или поставщик услуг по-прежнему обрабатывает функцию обратного вызова.
WSAEINTR
Блокирующий вызов сокета Windows 1.1 был отменен через WSACancelBlockingCall.
WSAEINVAL
Сокет не был привязан (например, с привязкой).
WSAEMSGSIZE
Сообщение было слишком большим для указанного буфера, и (только для ненадежных протоколов) все конечные части сообщения, которые не помещались в буфер, были удалены.
WSAENETDOWN
Произошел сбой сетевой подсистемы.
WSAENETRESET
Для сокета датаграмм эта ошибка указывает на то, что срок жизни истек.
WSAENOTCONN
Сокет не подключен (только сокеты, ориентированные на подключение).
WSAEWOULDBLOCK
Windows NT:

Перекрывающиеся сокеты. Существует слишком много невыполненных перекрывающихся запросов ввода-вывода. Неперекрывающиеся сокеты. Сокет помечается как неблокируемый, и операция получения не может быть завершена немедленно.

WSANOTINITIALISED
Перед использованием этой функции должен быть выполнен успешный вызов WSAStartup .
WSA_IO_PENDING
Перекрываемая операция успешно запущена, а ее завершение будет указано позже.
WSA_OPERATION_ABORTED
Перекрываемая операция была отменена из-за закрытия сокета.

Комментарии

Функция WSARecvFrom предоставляет функциональные возможности, помимо стандартной функции recvfrom , в трех важных областях:

  • Его можно использовать в сочетании с перекрывающимися сокетами для выполнения перекрывающихся операций получения.
  • Он позволяет указать несколько буферов приема, что делает его применимым к типу точечной и сборочной операций ввода-вывода.
  • Параметр lpFlags является как входным, так и выходным параметром, что позволяет приложениям чувствовать выходное состояние бита флага MSG_PARTIAL . Имейте в виду, что бит флага MSG_PARTIAL поддерживается не всеми протоколами.
Функция WSARecvFrom используется в основном в сокете без подключения, заданном параметром s. Локальный адрес сокета должен быть известен. Для серверных приложений это обычно выполняется явным образом с помощью привязки. Для клиентских приложений не рекомендуется использовать явную привязку. Для клиентских приложений, использующих эту функцию, сокет может быть неявно привязан к локальному адресу через sendto, WSASendTo или WSAJoinLeaf.

Для перекрывающихся сокетов эта функция используется для размещения одного или нескольких буферов, в которые будут помещены входящие данные по мере их доступности в (возможно, подключенном) сокете, после чего появляется указанное приложением указание завершения (вызов подпрограммы завершения или настройка объекта события). Если операция не завершается немедленно, окончательное состояние завершения извлекается с помощью процедуры завершения или WSAGetOverlappedResult. Кроме того, значения, указанные lpFrom и lpFromlen , не обновляются, пока не будет указано само завершение. Приложения не должны использовать или нарушать эти значения до тех пор, пока они не будут обновлены; поэтому приложение не должно использовать для этих параметров автоматические (то есть на основе стека) переменные.

Примечание Все операции ввода-вывода, инициированные данным потоком, отменяются при выходе из этого потока. Для перекрывающихся сокетов ожидающие асинхронные операции могут завершиться сбоем, если поток закрывается до завершения операций. Дополнительные сведения см. в разделе ExitThread .
 
Если lpOverlapped и lpCompletionRoutine имеют значение NULL, сокет в этой функции будет рассматриваться как неперекрытый сокет.

Для неперекрывающихся сокетов семантика блокировки идентична семантике стандартной функции WSARecv , а параметры lpOverlapped и lpCompletionRoutine игнорируются. Все данные, уже полученные и буферизируемые транспортом, будут скопированы в пользовательские буферы. В случае блокирующего сокета без данных, которые в настоящее время были получены и буферизованы транспортом, вызов будет блокироваться, пока не будут получены данные.

Буферы заполняются в том порядке, в котором они отображаются в массиве, указанном lpBuffers, и буферы упаковываются таким образом, чтобы не создавались отверстия.

Если эта функция выполняется перекрывающимся образом, поставщик услуг Winsock обязан захватить структуры WSABUF перед возвращением из этого вызова. Это позволяет приложениям создавать массивы WSABUF на основе стека, на которые указывает параметр lpBuffers .

Для типов сокетов без подключения адрес, с которого были получены данные, копируется в буфер, указанный lpFrom. Значение, на которое указывает lpFromlen , инициализируется размером этого буфера и изменяется по завершении, чтобы указать фактический размер хранящегося в нем адреса. Как упоминалось ранее для перекрывающихся сокетов, параметры lpFrom и lpFromlen не обновляются до завершения перекрывающихся операций ввода-вывода. Таким образом, память, на которую указывают эти параметры, должна оставаться доступной поставщику услуг и не может быть выделена в кадре стека приложения. Параметры lpFrom и lpFromlen игнорируются для сокетов, ориентированных на подключение.

Для сокетов в стиле потока байтов (например, тип SOCK_STREAM) входящие данные помещаются в буферы до тех пор, пока:

  • Буферы заполнены.
  • Соединение закрыто.
  • Внутренние буферизированные данные исчерпаны.
Независимо от того, заполняют ли входящие данные все буферы, для перекрывающихся сокетов появляется указание завершения. Для сокетов, ориентированных на сообщения, входящее сообщение помещается в буферы до общего размера буферов, а для перекрывающихся сокетов появляется указание завершения. Если сообщение больше буферов, буферы заполняются первой частью сообщения. Если функция MSG_PARTIAL поддерживается базовым поставщиком услуг, флаг MSG_PARTIAL устанавливается в lpFlags , и последующие операции получения будут извлекать остальную часть сообщения. Если MSG_PARTIAL не поддерживается, но протокол является надежным, WSARecvFrom создает ошибку WSAEMSGSIZE и последующую операцию получения с большим буфером можно использовать для получения всего сообщения. В противном случае (то есть протокол ненадежный и не поддерживает MSG_PARTIAL) лишние данные теряются, а WSARecvFrom создает ошибку WSAEMSGSIZE.

Параметр lpFlags можно использовать для влияния на поведение вызова функции за пределами параметров, указанных для связанного сокета. То есть семантика этой функции определяется параметрами сокета и параметром lpFlags . Последнее создается с помощью побитового оператора OR с любым из значений, перечисленных в следующей таблице.

Значение Значение
MSG_PEEK Предварительный просмотр входящих данных. Данные копируются в буфер, но не удаляются из входной очереди. Этот флаг действителен только для неперекрывающихся сокетов.
MSG_OOB Обрабатывает данные OOB.
MSG_PARTIAL Этот флаг предназначен только для сокетов, ориентированных на сообщения. В выходных данных этот флаг указывает, что данные являются частью сообщения, переданного отправителем. Остальные части сообщения будут передаваться в последующих операциях получения. Последующая операция получения с снятным флагом MSG_PARTIAL указывает на конец сообщения отправителя.

В качестве входного параметра этот флаг указывает, что операция получения должна завершиться, даже если поставщиком услуг была получена только часть сообщения.

 

Для сокетов, ориентированных на сообщения, бит MSG_PARTIAL задается в параметре lpFlags , если получено частичное сообщение. Если получено полное сообщение, MSG_PARTIAL очищается в lpFlags. В случае отложенного завершения значение, на которое указывает lpFlags , не обновляется. После указания завершения приложение должно вызвать WSAGetOverlappedResult и проверить флаги, на которые указывает параметр lpdwFlags .

Примечание При выполнении блокирующего вызова Winsock, например WSARecvFrom , с параметром lpOverlapped , имеющим значение NULL, Winsock может потребоваться дождаться сетевого события перед завершением вызова. В этой ситуации Winsock выполняет оповещенное ожидание, которое может быть прервано асинхронным вызовом процедуры (APC), запланированным в том же потоке. Выполнение другого блокирующего вызова Winsock внутри APC, который прервал текущий блокирующий вызов Winsock в том же потоке, приведет к неопределенному поведению, и клиенты Winsock никогда не должны пытаться его выполнять.
 

Перекрывающиеся сокеты ввода-вывода

Если перекрывающаяся операция завершается немедленно, WSARecvFrom возвращает нулевое значение, а параметр lpNumberOfBytesRecvd обновляется на количество полученных байтов, а также обновляются биты флага, указывающие параметром lpFlags . Если перекрывающаяся операция успешно инициирована и завершится позже, WSARecvFrom возвращает SOCKET_ERROR и указывает код ошибки WSA_IO_PENDING. В этом случае lpNumberOfBytesRecvd и lpFlags не обновляются. После завершения перекрывающейся операции объем передаваемых данных указывается либо с помощью параметра cbTransferred в подпрограмме завершения (если указано), либо с помощью параметра lpcbTransfer в WSAGetOverlappedResult. Значения флагов получаются либо с помощью параметра dwFlags подпрограммы завершения, либо путем проверки параметра lpdwFlagswSAGetOverlappedResult.

Функцию WSARecvFrom можно вызвать из подпрограммы завершения предыдущей функции WSARecv, WSARecvFrom, WSASend или WSASendTo . Для заданного сокета подпрограммы завершения ввода-вывода не будут вложенными. Это позволяет полностью выполнять передачу конфиденциальных во времени данных в контексте вытеснения.

Параметр lpOverlapped должен быть действителен в течение всего периода перекрываемой операции. Если одновременно выполняется несколько операций ввода-вывода, каждая из них должна ссылаться на отдельную структуру WSAOVERLAPPED .

Если параметр lpCompletionRoutine имеет значение NULL, параметр hEventобъекта lpOverlapped получает сигнал о завершении перекрываемой операции, если он содержит допустимый дескриптор объекта события. Приложение может использовать WSAWaitForMultipleEvents или WSAGetOverlappedResult для ожидания или опроса объекта события.

Если значение lpCompletionRoutine не равно NULL, параметр hEvent игнорируется и может использоваться приложением для передачи контекстных сведений в подпрограмму завершения. Вызывающий объект, который передает lpCompletionRoutine, отличный от NULL, а затем вызывает WSAGetOverlappedResult для того же перекрывающегося запроса ввода-вывода, может не задать для параметра fWait для этого вызова WSAGetOverlappedResult значение TRUE. В этом случае использование параметра hEvent не определено, и попытка ожидания параметра hEvent приведет к непредсказуемым результатам.

Процедура завершения соответствует тем же правилам, которые предусмотрены для процедур завершения файлового ввода-вывода Windows. Подпрограмма завершения не будет вызываться до тех пор, пока поток не будет находиться в состоянии ожидания, доступном для предупреждений, например при вызове функции WSAWaitForMultipleEvents с параметром fAlertable, равнымTRUE .

Если используется порт завершения операций ввода-вывода, а параметр lpCompletionRoutine и параметр hEvent имеют значение NULL, результатом операции является расписание для порта завершения ввода-вывода. Это происходит для всех успешных операций, независимо от того, выполняются ли операции немедленно или нет.

Поставщики транспорта позволяют приложению вызывать операции отправки и получения из контекста подпрограммы завершения ввода-вывода сокета и гарантируют, что для данного сокета подпрограммы завершения ввода-вывода не будут вложенными. Это позволяет полностью выполнять передачу конфиденциальных во времени данных в контексте вытеснения.

Ниже приведен прототип процедуры завершения.


void CALLBACK CompletionROUTINE(
  IN DWORD dwError, 
  IN DWORD cbTransferred, 
  IN LPWSAOVERLAPPED lpOverlapped, 
  IN DWORD dwFlags
);

CompletionRoutine — это заполнитель для имени определяемой приложением или библиотекой функции. DwError указывает состояние завершения для перекрываемой операции, как указано в lpOverlapped. CbTransferred указывает количество полученных байтов. Параметр dwFlags содержит сведения, которые появились бы в lpFlags , если бы операция получения была завершена немедленно. Эта функция не возвращает значение.

Возвращаясь из этой функции, можно использовать для этого сокета вызов другой подпрограммы отложенного завершения. При использовании WSAWaitForMultipleEvents все подпрограммы завершения ожидания вызываются, прежде чем ожидание потока с оповещениями будет удовлетворено кодом возврата WSA_IO_COMPLETION. Процедуры завершения могут вызываться в любом порядке, не обязательно в том же порядке, в каком выполняются перекрывающиеся операции. Однако размещенные буферы гарантированно заполняются в том же порядке, в который они указаны.

Пример кода

В следующем примере показано использование функции WSARecvFrom .
#ifndef UNICODE
#define UNICODE
#endif

#define WIN32_LEAN_AND_MEAN

#include <winsock2.h>
#include <Ws2tcpip.h>
#include <stdio.h>

int __cdecl main()
{

    WSADATA wsaData;
    WSABUF DataBuf;
    WSAOVERLAPPED Overlapped;

    SOCKET RecvSocket = INVALID_SOCKET;
    struct sockaddr_in RecvAddr;
    struct sockaddr_in SenderAddr;

    int SenderAddrSize = sizeof (SenderAddr);
    u_short Port = 27015;

    char RecvBuf[1024];
    int BufLen = 1024;
    DWORD BytesRecv = 0;
    DWORD Flags = 0;

    int err = 0;
    int rc;
    int retval = 0;
    
    //-----------------------------------------------
    // Initialize Winsock
    rc = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (rc != 0) {
        /* Could not find a usable Winsock DLL */
        wprintf(L"WSAStartup failed with error: %ld\n", rc);
        return 1;
    }

    // Make sure the Overlapped struct is zeroed out
    SecureZeroMemory((PVOID) &Overlapped, sizeof(WSAOVERLAPPED) );

    // Create an event handle and setup the overlapped structure.
    Overlapped.hEvent = WSACreateEvent();
    if (Overlapped.hEvent == NULL) {
        wprintf(L"WSACreateEvent failed with error: %d\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }
    //-----------------------------------------------
    // Create a receiver socket to receive datagrams
    RecvSocket = WSASocket(AF_INET,
                           SOCK_DGRAM,
                           IPPROTO_UDP, NULL, 0, WSA_FLAG_OVERLAPPED);

    if (RecvSocket == INVALID_SOCKET) {
        /* Could not open a socket */
        wprintf(L"WSASocket failed with error: %ld\n", WSAGetLastError());
        WSACloseEvent(Overlapped.hEvent);
        WSACleanup();
        return 1;
    }
    //-----------------------------------------------
    // Bind the socket to any address and the specified port.
    RecvAddr.sin_family = AF_INET;
    RecvAddr.sin_port = htons(Port);
    RecvAddr.sin_addr.s_addr = htonl(INADDR_ANY);

    rc = bind(RecvSocket, (SOCKADDR *) & RecvAddr, sizeof (RecvAddr));
    if (rc != 0) {
        /* Bind to the socket failed */
        wprintf(L"bind failed with error: %ld\n", WSAGetLastError());
        WSACloseEvent(Overlapped.hEvent);
        closesocket(RecvSocket);
        WSACleanup();
        return 1;
    }

    //-----------------------------------------------
    // Call the recvfrom function to receive datagrams
    // on the bound socket.
    DataBuf.len = BufLen;
    DataBuf.buf = RecvBuf;
    wprintf(L"Listening for incoming datagrams on port=%d\n", Port);
    rc = WSARecvFrom(RecvSocket,
                      &DataBuf,
                      1,
                      &BytesRecv,
                      &Flags,
                      (SOCKADDR *) & SenderAddr,
                      &SenderAddrSize, &Overlapped, NULL);

    if (rc != 0) {
        err = WSAGetLastError();
        if (err != WSA_IO_PENDING) {
            wprintf(L"WSARecvFrom failed with error: %ld\n", err);
            WSACloseEvent(Overlapped.hEvent);
            closesocket(RecvSocket);
            WSACleanup();
            return 1;
        }
        else {
            rc = WSAWaitForMultipleEvents(1, &Overlapped.hEvent, TRUE, INFINITE, TRUE);
            if (rc == WSA_WAIT_FAILED) {
                wprintf(L"WSAWaitForMultipleEvents failed with error: %d\n", WSAGetLastError());
                retval = 1;
            }

            rc = WSAGetOverlappedResult(RecvSocket, &Overlapped, &BytesRecv,
                                FALSE, &Flags);
            if (rc == FALSE) {
                wprintf(L"WSArecvFrom failed with error: %d\n", WSAGetLastError());
                retval = 1;
            }
            else
                wprintf(L"Number of received bytes = %d\n", BytesRecv);
                
            wprintf(L"Finished receiving. Closing socket.\n");
        }
        
    }
    //---------------------------------------------
    // When the application is finished receiving, close the socket.

    WSACloseEvent(Overlapped.hEvent);
    closesocket(RecvSocket);
    wprintf(L"Exiting.\n");

    //---------------------------------------------
    // Clean up and quit.
    WSACleanup();
    return (retval);
}

Windows Phone 8. Эта функция поддерживается для приложений Магазина Windows Phone на Windows Phone 8 и более поздних версиях.

Windows 8.1 и Windows Server 2012 R2: эта функция поддерживается для приложений Магазина Windows на Windows 8.1, Windows Server 2012 R2 и более поздних версий.

Требования

   
Минимальная версия клиента Windows 8.1, Windows Vista [классические приложения | Приложения UWP]
Минимальная версия сервера Windows Server 2003 [классические приложения | Приложения UWP]
Целевая платформа Windows
Header winsock2.h
Библиотека Ws2_32.lib
DLL Ws2_32.dll

См. также раздел

WSABUF

WSACloseEvent

WSACreateEvent

WSAGetOverlappedResult

WSAOVERLAPPED

WSASend

WSASendTo

WSASocket

WSAWaitForMultipleEvents

Функции Winsock

Справочник по Winsock

Sendto