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
нужно задать указатель на процедуру завершения, описанную в программе. Процедура завершения должна иметь прототип, приведенный в листинге 2.72.
Листинг 2.72. Прототип процедуры завершения
// ***** Описание на C++ *****
void CALLBACK CompletionROUTINE(DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED lpOverlapped, DWORD dwFlags);
// ***** Описание на Delphi *****
TWSAOverlappedCompletionRoutine =
procedure(dwError: DWORD; cbTransferred: DWORD; lpOverlapped: PWSAOverlapped; dwFlags: DWORD); stdcall;
При использовании процедур завершения в функцию WSARecv
также нужно передавать указатель на запись TWSAOverlapped
через параметр lpOverlapped
, но значение поля hEvent
этой структуры игнорируется. Вместо взведения события при завершении операции будет вызвана процедура, указанная в качестве параметра функции WSARecv
. Указатель на структуру, заданный при вызове WSARecv
, передается в процедуру завершения через параметр lpOverlapped
. Смысл остальных параметров очевиден: dwError
— это код ошибки (или ноль, если операция завершена успешно), cbTransferred
— число полученных байтов (само полученное сообщение копируется в буферы, указанные при вызове функции WSARecv
), a dwFlags
— флаги.
Процедура завершения всегда выполняется в той нити, которая инициировала начало операции перекрытого ввода-вывода. Но система не может прерывать нить для выполнения процедуры завершения в любой удобный ей момент — нить должна перейти в состояние ожидания. В это состояние ее можно перевести, например, с помощью функции SleepEx
, имеющей следующий прототип:
function SleepEx(dwMilliseconds: DWORD; bAlertable: BOOL); DWORD;
Функция SleepEx
является частью стандартного API системы и импортируется модулем Windows. Она переводит нить в состояние ожидания. Параметр dwMilliseconds
задает время ожидания в миллисекундах (или значение INFINITE
для бесконечного ожидания). Параметр bAlertable указывает, допустимо ли прерывание состояния ожидания для выполнения процедуры завершения. Если bAlertable
равен False
, функция SleepEx
ведет себя так же как функция Sleep
, т.е. просто приостанавливает работу нити на заданное время. Если bAlertable
равен True
, нить может быть выведена системой из состояния ожидания раньше, чем истечет заданное время, если возникнет необходимость выполнить процедуру завершения. О причине завершения ожидания программа может судить по результату, возвращаемому функцией SleepEx
: ноль в случае завершения по тайм-ауту и WAIT_IO_COMPLETION
в случае завершения из-за выполнения процедуры завершения (в последнем случае сначала выполняется процедура завершения, а потом только происходит возврат из функции SleepEx
). Если завершились несколько операций перекрытого ввода-вывода, в результате выполнения SleepEx
будут вызваны процедуры завершения для всех этих операций.
Существует также возможность ожидать выполнения процедуры завершения одновременно с ожиданием взведения событий с помощью функции WSAWaitForMultipleEvents
. Напомним, что у этой функции также есть параметр fAlertable
. Если задать его равным True
, то при необходимости выполнения процедуры завершения функция WSAWaitForMultipleEvents
, подобно функции SleepEx
, выполняет эту процедуру и возвращает WAIT_IO_COMPLETION
.
Читать дальше
Конец ознакомительного отрывка
Купить книгу