Поделиться через


Функция обратного вызова LPWSPRECVFROM (ws2spi.h)

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

Синтаксис

LPWSPRECVFROM Lpwsprecvfrom;

int Lpwsprecvfrom(
  [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\]    LPWSATHREADID lpThreadId,
  [in, out] LPINT lpErrno
)
{...}

Параметры

[in] s

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

[in, out] lpBuffers

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

[in] dwBufferCount

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

[out] lpNumberOfBytesRecvd

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

[in, out] lpFlags

Указатель на флаги.

[out] lpFrom

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

[in, out] lpFromlen

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

[in] lpOverlapped

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

[in] lpCompletionRoutine

Тип: _In_opt_ LPWSAOVERLAPPED_COMPLETION_ROUTINE

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

\\[in\\] lpThreadId

Указатель на структуру WSATHREADID , которая будет использоваться поставщиком при последующем вызове WPUQueueApc. Поставщик должен хранить указанную структуру WSATHREADID (а не указатель на нее) до тех пор, пока не будет возвращена функция WPUQueueApc .

[in, out] lpErrno

Указатель на код ошибки.

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

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

Код ошибки Значение
WSAENETDOWN
Произошел сбой сетевой подсистемы.
WSAEFAULT
Недопустимый параметр lpFromlen : буфер lpFrom был слишком мал для размещения однорангового адреса или lpbuffers не полностью содержался в допустимой части адресного пространства пользователя.
WSAEINTR
(Блокирующий) вызов был отменен через LPWSPCancelBlockingCall.
WSAEINPROGRESS
Выполняется блокировка вызова сокетов Windows или поставщик услуг по-прежнему обрабатывает функцию обратного вызова.
WSAEINVAL
Сокет не был привязан (например, с LPWSPBind) или сокет не создан с перекрывающимся флагом.
WSAEISCONN
Сокет подключен. Эта функция не разрешена с подключенным сокетом, независимо от того, является ли сокет ориентированным на подключение или без подключения.
WSAENETRESET
Подключение было разорвано из-за активности активности при обнаружении сбоя во время выполнения операции.
WSAENOTSOCK
Дескриптор не является сокетом.
WSAEOPNOTSUPP
MSG_OOB указано, но сокет не является типом потока, например типом SOCK_STREAM, данные OOB не поддерживаются в домене связи, связанном с этим сокетом, или сокет является однонаправленным и поддерживает только операции отправки.
WSAESHUTDOWN
Сокет завершен; невозможно запустить LPWSPRecvFrom в сокете после вызова LPWSPShutdownс параметром SD_RECEIVE или SD_BOTH.
WSAEWOULDBLOCK
**Windows NT:**
Перекрывающиеся сокеты. Существует слишком много невыполненных перекрывающихся запросов ввода-вывода. Неперекрывающиеся сокеты. Сокет помечается как неблокируемый, и операция получения не может быть завершена немедленно.
WSAEMSGSIZE
Сообщение было слишком большим, чтобы поместиться в указанный буфер, и (только для ненадежных протоколов) все конечные части сообщения, которые не помещались в буфер, были удалены.
WSAECONNRESET
Виртуальное подключение было сброшено удаленной стороной путем прерывания. Приложение должно закрыть сокет, поскольку он больше не может использоваться. В сокете датаграммы UDP эта ошибка указывает на то, что предыдущая операция отправки привела к сообщению ICMP "Порт недоступен".
WSAEDISCON
Сокеты ориентированы на сообщения, а виртуальная цепь была корректно закрыта удаленной стороной.
WSA_IO_PENDING
Перекрываемая операция была успешно инициирована, а завершение будет указано позже.
WSA_OPERATION_ABORTED
Операция перекрытия была отменена из-за закрытия сокета.

Комментарии

Функция LPWSPRecvFrom используется в основном в сокете без подключения, заданном параметром s . Сокет не должен быть подключен. Локальный адрес сокета должен быть известен. Это можно сделать явно через LPWSPBind или неявно через LPWSPSendTo или LPWSPJoinLeaf.

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

Если и lpOverlapped , и lpCompletionRoutine имеют значение NULL, сокет в этой функции будет рассматриваться как неперекрытый сокет.

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

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

Массив структур WSABUF , на который указывает параметр lpBuffers , является временным. Если эта операция завершается перекрывающимся образом, поставщик услуг отвечает за сбор этого массива указателей на структуры WSABUF перед возвращением из этого вызова. Это позволяет клиентам WINDOWS Sockets SPI создавать массивы WSABUF на основе стека.

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

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

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

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

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

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

 

 

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

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

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

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

Если параметр lpCompletionRoutine имеет значение NULL, поставщик службы сообщает члену hEventобъекта lpOverlapped , когда перекрываемая операция завершается, если она содержит допустимый дескриптор объекта события. Клиент WINDOWS Sockets SPI может использовать LPWSPGetOverlappedResult для ожидания или опроса объекта события.

Если значение lpCompletionRoutine не равно NULL, элемент hEvent игнорируется и может использоваться клиентом SPI сокетов Windows для передачи контекстных сведений в подпрограмму завершения. Поставщик услуг отвечает за организацию вызова указанной клиентом процедуры завершения после завершения перекрывающейся операции. Так как подпрограмма завершения должна выполняться в контексте того же потока, который инициировал перекрывающуюся операцию, ее нельзя вызвать непосредственно от поставщика услуг. Ws2_32.dll предлагает механизм асинхронного вызова процедур (APC) для упрощения вызова процедур завершения.

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

WPUQueueApc принимает в качестве входных параметров указатель на структуру WSATHREADID (предоставленную поставщику через входной параметр lpThreadId ), указатель на вызываемую функцию APC и значение контекста, которое затем передается в функцию APC. Так как доступно только одно значение контекста, сама функция APC не может быть указанной клиентом подпрограммой завершения. Поставщик услуг должен вместо этого предоставить указатель на собственную функцию APC, которая использует предоставленное значение контекста для доступа к необходимым сведениям о результатах для перекрываемой операции, а затем вызывает подпрограмму завершения, указанную клиентом.

Ниже приведен прототип процедуры завершения, предоставляемой клиентом.

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

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

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

Примечание

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

Требования

   
Минимальная версия клиента Windows 2000 Professional [только классические приложения]
Минимальная версия сервера Windows 2000 Server [только классические приложения]
Верхняя часть ws2spi.h

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

WPUQueueApc

LPWSPGetOverlappedResult

LPWSPSocket