Чтение онлайн

на главную - закладки

Жанры

О чём не пишут в книгах по Delphi

Григорьев Антон Борисович

Шрифт:

 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
.

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

TWSAOverlapped
. Процедура завершения получает указатель на тот экземпляр, который использовался для начала завершившейся операции. Можно сравнил, указатель с теми, которые были заданы при запуске операций перекрытого ввода-вывода, и определить, какая из них завершилась. Это не всегда бывает удобно из-за необходимости где-то хранить список
указателей, заданных при начале операций перекрытого ввода-вывода. Существуют еще два варианта решения этой проблемы. Первый заключается в создании своей процедуры завершения для каждой из выполняющихся параллельно операций. Этот способ приводит к получению громоздкого кода и может быть неудобен, если число одновременно выполняющихся операций заранее неизвестно. Он целесообразен только при одновременном выполнении разнородных операций, требующих разных алгоритмов при обработке их завершения. Другой вариант предлагается в MSDN. Так как при работе через процедуры завершения значение поля
hEvent
структуры
TWSAOverlapped
игнорируется системой, программа может записать туда любое 32-битное значение и с его помощью определить, какая из операций завершена. В строго типизированном языке, каким является Delphi, подобное смещение типа дескриптора и целого выглядит весьма непривлекательно, но, к сожалению, это лучшее из того, что нам предлагают разработчики WinSock API.

Механизм процедур завершения допускает определение статуса операции с с помощью функции

WSAGetOverlappedResult
, но ее параметр
fWait
обязательно должен быть равен
False
, потому что события, необходимые для выполнения ожидания, не взводятся, и попытка дождаться окончания операции может привести к блокировке работы нити.

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

Листинг 2.73. Перекрытый ввод-вывод с использованием процедуры завершения

var

 S: TSocket;

 Overlapped: TWSAOverlapped;

 BufPtr: TWSABuf;

 RecvBuf: array[1..100] of Char;

 Cnt, Flags: Cardinal;

 Connected: Boolean;

procedure GetData(Err, Cnt:DWORD; OvPtr: PWSAOverlapped; Flags: DWORD): stdcall;

begin

 if Err <> 0 then

 begin

// Произошла ошибка. Соединение нужно устанавливать заново

closesocket(S);

Connected := False;

 end;

 else

 begin

// Получены данные, обрабатываем

......

// Запускаем новую операцию перекрытого чтения

Flags := 0;

WSARecv(S, @BufPtr, 1, Cnt, Flags, OvPtr, GetData);

 end;

end;

procedure ProcessConnection;

begin

 // Устанавливаем начальное состояние - сокет не соединен

 Connected := False;

 // Задаем буфер

 BufPtr.Buf := @RecvBuf;

 BufPtr.Len := SizeOf(RecvBuf);

 while True do

 begin

if not Connected then

begin

Connected := True;

// Создаем и подключаем сокет

S := socket(AF_INET, SOCK_STREAM, 0);

connect(S, ...);

// Запускаем первую для данного сокета операцию чтения

Flags := 0;

WSARecv(S, @BufPtr, 1, Cnt, Flags, @Overlapped, GetData);

end;

// Позволяем системе выполнить процедуру завершения,

// если это необходимо

Поделиться:
Популярные книги

Шесть тайных свиданий мисс Недотроги

Суббота Светлана
Любовные романы:
любовно-фантастические романы
эро литература
7.75
рейтинг книги
Шесть тайных свиданий мисс Недотроги

Я еще не барон

Дрейк Сириус
1. Дорогой барон!
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Я еще не барон

Седьмая жена короля

Шёпот Светлана
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Седьмая жена короля

Не верь мне

Рам Янка
7. Самбисты
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Не верь мне

Газлайтер. Том 12

Володин Григорий Григорьевич
12. История Телепата
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Газлайтер. Том 12

Жандарм

Семин Никита
1. Жандарм
Фантастика:
попаданцы
альтернативная история
аниме
4.11
рейтинг книги
Жандарм

Архонт

Прокофьев Роман Юрьевич
5. Стеллар
Фантастика:
боевая фантастика
рпг
7.80
рейтинг книги
Архонт

Волк 7: Лихие 90-е

Киров Никита
7. Волков
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Волк 7: Лихие 90-е

Целитель

Первухин Андрей Евгеньевич
1. Целитель
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Целитель

Кодекс Охотника. Книга XXIV

Винокуров Юрий
24. Кодекс Охотника
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Охотника. Книга XXIV

Менталист. Конфронтация

Еслер Андрей
2. Выиграть у времени
Фантастика:
боевая фантастика
6.90
рейтинг книги
Менталист. Конфронтация

Восход. Солнцев. Книга IX

Скабер Артемий
9. Голос Бога
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Восход. Солнцев. Книга IX

Сломанная кукла

Рам Янка
5. Серьёзные мальчики в форме
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Сломанная кукла

Свет во мраке

Михайлов Дем Алексеевич
8. Изгой
Фантастика:
фэнтези
7.30
рейтинг книги
Свет во мраке