function WSARecv(S: TSocket; lpBuffers: PWSABuf; dwBufferCount: DWORD; var NumberOfBytesRecvd: DWORD; var Flags: DWORD; lpOverlapped: PWSAOverlapped; lpCompletionRoutine: TWSAOverlappedCompletionRoutine): Integer;
Перекрытым вводом-выводом управляют два последних параметра функции, но WSARecv
обладает и другими дополнительными по сравнению с функцией recv
возможностями, не связанными с перекрытым вводом-выводом. Если оба этих параметра равны nil
, или сокет создан без указания флага WSA_FLAG_OVERLAPPED
, функция работает в обычном блокирующем или неблокирующем режиме, который установлен для сокета. При этом ее поведение отличается от поведения функции recv
только тремя незначительными аспектами: во-первых, вместо одного буфера ей можно передать несколько, заполняемых последовательно. Во-вторых, флаги передаются ей не как значение, а как параметр-переменная, и при некоторых условиях функция WSARecv
может их изменять (при использовании TCP и UDP флаги никогда не меняются, поэтому мы не будем рассматривать здесь эту возможность). В-третьих, при успешном завершении функция WSARecv
возвращает ноль, а не число прочитанных байтов (последнее возвращается через параметр lpNumberOfBytesRecvd
).
Буферы, в которые нужно поместить данные, передаются функции WSARecv
через параметр lpBuffers
. Он содержит указатель на начало массива структур TWSABuf
, а параметр dwBufferCount
— число элементов в этом массиве. Ранее мы знакомились со структурой TWSABuf
(см. листинг 2.39): она содержит указатель на начало буфера и его размер. Соответственно, массив таких структур определяет набор буферов. При чтении данных заполнение буферов начинается с первого буфера в массиве lpBuffers
, затем, если в нем не хватает места, заполняется второй буфер и т.д. Функция не переходит к следующему буферу, пока не заполнит предыдущий до последнего байта. Таким образом, данные, получаемые с помощью функции WSARecv
, могут быть помещены в несколько несвязных областей памяти, что иногда бывает удобно, если принимаемые сообщения имеют строго определенный формат с фиксированными размерами компонентов пакета: в этом случае можно каждый компонент поместить в свой независимый буфер.
Теперь переходим непосредственно к рассмотрению перекрытого ввода-вывода на основе событий. Для реализации этого режима при вызове функции WSARecv
параметр lpCompletionRoutine
должен быть равен nil
, а через параметр lpOverlapped
передается указатель на запись TWSAOverlapped
, которая определена следующим образом (листинг 2.69).
Листинг 2 69. Тип TWSAOverlapped
//***** Описание на C++ *****
struct _WSAOVERLAPPED {
DWORD Internal;
DWORD InternalHigh;
DWORD Offset;
DWORD OffsetHigh;
WSAEVENT hEvent;
} WSAOVERLAPPED, *LPWSAOVEPLAPPED;
// ***** Описание на Delphi *****
PWSAOverlapped = ^TWSAOverlapped;
TWSAOverlapped = packed record
Internal, InternalHigh, Offer, OffsetHigh: DWORD;
hEvent: TWSAEvent;
end;
Поля Internal
, InternalHigh
, Offset
и OffsetHigh
предназначены для внутреннего использования системой, программа не должна выполнять никаких действий с ними. Поле hEvent
задает событие, которое будет взведено при завершении операции перекрытого ввода-вывода. Если на момент вызова функции WSARecv
данные в буфере сокета отсутствуют, она вернет значение SOCKET_ERROR
, а функция WSAGetLastError
— WSA_IO_PENDING
(997). Это значит, что операция начала выполняться в фоновом режиме. В этом случае функция WSARecv
не изменяет значения параметров NumberOfBytesRecvd
и Flag
. Поля структуры TWSAOverlapped
при этом также модифицируются, и эта структура должна быть сохранена программой в неприкосновенности до окончания операции перекрытого ввода-вывода. После окончания операции будет взведено событие, указанное в поле hEvent
параметра lpOverlapped
. При необходимости программа может дождаться этого взведения с помощью функции WSAWaitForMultipleEvents
.
Как только запрос будет выполнен, в буферах, переданных через параметр lpBuffers
, оказываются принятые данные. Но знания одного только факта, что запрос выполнен, недостаточно, чтобы этими данными воспользоваться, потому что, во-первых, неизвестен размер этих данных, а во-вторых, неизвестно, успешно ли завершена операция перекрытого ввода-вывода. Для получения недостающей информации служит функция WSAGetOverlappedResult
, прототип которой приведен в листинге 2.70.
Листинг 2.70. Функция WSAGetOverlappedResult
// ***** Описание на C++ *****
Читать дальше
Конец ознакомительного отрывка
Купить книгу