В принципе, программа может вообще не использовать события для отслеживания завершения операции ввода-вывода, а вызывать вместо этого время от времени функцию WSAGetOverlappedResult
WSARecv
можно указать нулевое значение события hEvent
. Но следует иметь в виду, что при вызове функции WSAGetOverlappedResult
с параметром fWait
, равным True
, указанное событие служит для ожидания завершения операции, и если событие не задано, возникнет ошибка. Таким образом, если событие не используется, функция WSAGetOverlappedResult
не может вызываться в режиме ожидания.Отдельно рассмотрим ситуацию, когда на момент вызова функции WSARecv
lpOverlapped
во входном буфере сокета есть данные. В этом случае функция отработает так же, как и в неперекрытом режиме, т.е. изменит значения параметров NumberOfBytesRecvd
и Flags
и вернет ноль, свидетельствующий об успешном выполнении функции. Но при этом событие будет взведено, а в структуру lpOverlapped
будет внесена вся необходимая информация. Благодаря этому последующие вызовы функций WSAWaitForMultipleEvents
и WSAGetOverlappedResult
будут выполняться корректно, т.е. таким образом, как если бы функция WSARecv
завершилась с ошибкой WSA_IO_PENDING
, и сразу после этого в буфер сокета поступили данные. Это позволяет выполнить обработку результатов операций перекрытого ввода-вывода с помощью одного и того же кода независимо от того, были ли в буфере сокета данные на момент начала операции или нет.Новая операция перекрытого ввода-вывода может быть начата до того, как закончится предыдущая. Это удобно при работе с несколькими сокетами: можно выполнять операции с ними параллельно в фоновом режиме, получая уведомления о завершении каждой из операций.
В MSDN не написано явно, что будет, если вызвать для сокета функцию WSARecv
В качестве примера реализации перекрытого ввода-вывода рассмотрим, ситуацию, когда программа начинает операцию чтения данных из сокета, время от времени проверяя статус операции (листинг 2.71). События в этом примере не используются, проверка осуществляется с помощью функции WSAGetOverlappedResult
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 программа
// не устанавливает
Overlapped.hEvent := 0;
Flags := 0;
// Начало операции перекрытого получения данных
WSARecv(S, @BufPtr, 1, Cnt, Flags, @Overlapped, nil);
while True do
begin
if WSAGetOverlappedResult(S, @Overlapped, Cnt, False, Flags) then
begin
// Данные получены, находятся в RecvBuf, обрабатываем
......
// Выходим из цикла Break;
end
else if WSAGetLastError <> WSA_IO_INCOMPLETE then
begin
// Произошла ошибка, анализируем ее
......
// Выходим из цикла
Break;
end
else
begin
// Операция чтения не завершена
// Занимаемся другими действиями
end;
end;
Теперь перейдем к рассмотрению перекрытого ввода-вывода на основе процедур завершения. Для этого при вызове функции WSARecv