function WSAGetOverlappedResult(S: TSocket; lpOverlapped: PWSAOverlapped; var cbTransfer: DWORD; fWait: BOOL; var Flags: DWORD): BOOL;
Параметры
S
и
lpOverlapped
функции
WSAGetOverlappedResult
определяют coкет
и операцию перекрытого ввода-вывода, информацию о которой требуется получить. Их значения должны совпадать со значениями соответствующих параметров, переданных функции
WSARecv
. Через параметр
cbTransfer
возвращается число полученных байтов, а через параметр
Flags
— флаги (напомним, что в случае TCP и UDP флаги не модифицируются, и выходное значение параметра
Flags
будет равно входному значению параметра
Flags
функции
WSARecv
).
Допускается вызов функции
WSAGetOverlappedResult
до того, как операция перекрытого ввода-вывода будет завершена. В этом случае поведение функции зависит от параметра
fWait
. Если он равен
True
, функция переводит нить в состояние ожидания до тех пор, пока операция не будет завершена. Если он равен
False
, функция завершается немедленно с ошибкой
WSA_IO_INCOMPLETE
(996).
Функция
WSAGetOverlappedResult
возвращает
True
, если операция перекрытого ввода-вывода успешно завершена, и
False
, если произошли какие-то ошибки. Ошибка может возникнуть в одном из трех случаев:
1. Операция перекрытого ввода-вывода еще не завершена, а параметр
fWait
равен
False
.
2. Операция перекрытого ввода-вывода завершилась с ошибкой (например, из-за разрыва связи).
3. Параметры, переданные функции
WSAGetOverlappedResult
, имеют некорректные значения.
Точную причину, по которой функция вернула
False
, можно установить стандартным образом — по коду ошибки, возвращаемому функцией
WSAGetLastError
.
В принципе, программа может вообще не использовать события для отслеживания завершения операции ввода-вывода, а вызывать вместо этого время от времени функцию
WSAGetOverlappedResult
в удобные для себя моменты. Тогда при вызове функции
WSARecv
можно указать нулевое значение события
hEvent
. Но следует иметь в виду, что при вызове функции
WSAGetOverlappedResult
с параметром
fWait
, равным
True
, указанное событие служит для ожидания завершения операции, и если событие не задано, возникнет ошибка. Таким образом, если событие не используется, функция
WSAGetOverlappedResult
не может вызываться в режиме ожидания.
Отдельно рассмотрим ситуацию, когда на момент вызова функции
WSARecv
с ненулевым параметром
lpOverlapped
во входном буфере сокета есть данные. В этом случае функция отработает так же, как и в неперекрытом режиме, т.е. изменит значения параметров
NumberOfBytesRecvd
и
Flags
и вернет ноль, свидетельствующий об успешном выполнении функции. Но при этом событие будет взведено, а в структуру
lpOverlapped
будет внесена вся необходимая информация. Благодаря этому последующие вызовы функций
WSAWaitForMultipleEvents
и
WSAGetOverlappedResult
будут выполняться корректно, т.е. таким образом, как если бы функция
WSARecv
завершилась с ошибкой
WSA_IO_PENDING
, и сразу после этого в буфер сокета поступили данные. Это позволяет выполнить обработку результатов операций перекрытого ввода-вывода с помощью одного и того же кода независимо от того, были ли в буфере сокета данные на момент начала операции или нет.
Новая операция перекрытого ввода-вывода может быть начата до того, как закончится предыдущая. Это удобно при работе с несколькими сокетами: можно выполнять операции с ними параллельно в фоновом режиме, получая уведомления о завершении каждой из операций.
В MSDN не написано явно, что будет, если вызвать для сокета функцию
WSARecv
повторно, до того как будет завершена предыдущая операция перекрытого чтения (но запрета на такие действия тоже нет). Эксперименты показывают, что в этом случае операции перекрытого чтения встают в очередь, т.е. первый полученный сокетом пакет приводит к завершению операции, начатой первой, второй пакет — к завершению операции, начатой второй, и т.д. Но поскольку это явно не документировано, лучше не полагаться на то, что такой порядок будет всегда соблюдаться.
В качестве примера реализации перекрытого ввода-вывода рассмотрим, ситуацию, когда программа начинает операцию чтения данных из сокета, время от времени проверяя статус операции (листинг 2.71). События в этом примере не используются, проверка осуществляется с помощью функции
WSAGetOverlappedResult
.
Листинг 2.71. Перекрытый ввод-вывод с использованием функции
WSAGetOverlappedResult
var
S: TSocket;
Overlapped: TWSAOverlapped;
BufPtr: TWSABuf;
RecvBuf: array[1..100] of Char;
Cnt, Flags: Cardinal;
begin
// Инициализация WinSock, создание сокета S, привязка его к адресу
......
// Подготовка структуры, задавшей буфер
BufPtr.Buf := @RBuf;
BufPtr.Len := SizeOf(RBuf);
// Подготовка структуры TWSAOverlapped
// Поля Internal, InternalHigh, Offset, OffsetHigh программа