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

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

Жанры

О чём не пишут в книгах по 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;

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

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

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

Часовая башня

Щерба Наталья Васильевна
3. Часодеи
Фантастика:
фэнтези
9.43
рейтинг книги
Часовая башня

Попаданка в Измену или замуж за дракона

Жарова Анита
Любовные романы:
любовно-фантастические романы
6.25
рейтинг книги
Попаданка в Измену или замуж за дракона

На границе империй. Том 9. Часть 3

INDIGO
16. Фортуна дама переменчивая
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
На границе империй. Том 9. Часть 3

Жена на пробу, или Хозяйка проклятого замка

Васина Илана
Фантастика:
попаданцы
фэнтези
5.00
рейтинг книги
Жена на пробу, или Хозяйка проклятого замка

Ваше Сиятельство

Моури Эрли
1. Ваше Сиятельство
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Ваше Сиятельство

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

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

Инвестиго, из медика в маги

Рэд Илья
1. Инвестиго
Фантастика:
фэнтези
городское фэнтези
попаданцы
5.00
рейтинг книги
Инвестиго, из медика в маги

Надуй щеки!

Вишневский Сергей Викторович
1. Чеболь за партой
Фантастика:
попаданцы
дорама
5.00
рейтинг книги
Надуй щеки!

Случайная свадьба (+ Бонус)

Тоцка Тала
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Случайная свадьба (+ Бонус)

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

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

Мастер Разума III

Кронос Александр
3. Мастер Разума
Фантастика:
героическая фантастика
попаданцы
аниме
5.25
рейтинг книги
Мастер Разума III

Наследник 2

Шимохин Дмитрий
2. Старицкий
Фантастика:
попаданцы
альтернативная история
фэнтези
5.75
рейтинг книги
Наследник 2

Неучтенный. Дилогия

Муравьёв Константин Николаевич
Неучтенный
Фантастика:
боевая фантастика
попаданцы
7.98
рейтинг книги
Неучтенный. Дилогия

Светлая тьма. Советник

Шмаков Алексей Семенович
6. Светлая Тьма
Фантастика:
юмористическое фэнтези
городское фэнтези
аниме
сказочная фантастика
фэнтези
5.00
рейтинг книги
Светлая тьма. Советник