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

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

Жанры

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

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

Шрифт:

TWSANetworkEvents = packed record

 lNetworkEvents: LongInt;

 iErrorCode: array[0..FD_MAX_EVENTS - 1] of Integer;

end;

Константа

FD_MAX_EVENTS
определяет количество разных типов событий и в данной реализации равна 10.

Значения констант

FD_XXX
представляют собой степени двойки, поэтому их можно объединять операцией арифметического ИЛИ без потери информации. Поле
lNetworkEvents
является таким объединением всех констант, задающих события,
которые происходили на сокете. Другими словами, если результат операции (
lNetworkEvents and FD_XXX
) не равен нулю, значит, событие
FD_XXX
происходило на сокете.

Массив

iErrorCode
содержит информацию об ошибках, которыми сопровождались события
FD_XXX
. Для каждого события
FD_XXX
определена соответствующая константа
FD_XXX_BIT
(т.е. константы
FD_READ_BIT
,
FD_WRITE_BIT
и т.д.). Элемент массива с индексом
FD_XXX_BIT
содержит информацию об ошибке, связанной с событием
FD_XXX
. Если операция прошла успешно, этот элемент содержит ноль, в противном случае — код ошибки, которую в аналогичной ситуации вернула бы функция
WSAGetLastError
после выполнения соответствующей операции на синхронном сокете.

Таким образом, программа, использующая асинхронный режим, основанный на событиях, должна выполнить следующие действия. Во-первых, создать сокет и установить соединение. Во-вторых, привязать события

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

Сокетные события могут взводиться не только в результате событий на сокете, но и вручную, с помощью функции

WSASetEvent
. Это дает нити, вызвавшей функцию
WSAWaitForMultipleEvents
, возможность выходить из состояния ожидания не только при возникновении событий на сокете, но и по сигналам от других нитей. Типичная область применения этой возможности — для тех случаев, когда программа может как отвечать на запросы от удаленного партнера, так и отправлять ему что-то по собственной инициативе. В этом случае могут использоваться два сокетных события: одно связывается с событием
FD_READ
для оповещения о поступлении данных, а второе не связывается ни с одним из событий
FD_XXX
, а устанавливается другой нитью тогда, когда необходимо отправить сообщение. Нить, работающая с сокетом, ожидает взведения одного из этих событий и в зависимости от того, какое из них взведено, читает или отправляет данные.

В листинге 2.62 приведен пример кода такой нити. Она задействует три сокетных события: одно для уведомления о событиях на сокете, второе — для уведомления о необходимости отправить данные, третье — для уведомления о необходимости завершиться. В данном примере мы предполагаем, что, во-первых, сокет создан и подключен до создания нити и передается ей в качестве параметра, а во-вторых, три сокетных события хранятся в глобальном массиве

SockEvents: array[0..2] of TWSAEvent
, причем нулевой элемент этого массива содержит событие, связываемое с событиями
FD_XXX
,
первый элемент — событие отправки данных, второй — событие завершения нити. Прототип функции, образующей нить, совместим с функцией
BeginThread
из модуля
SysUtils
.

Листинг 2.62. Схема нити, использующей события асинхронного сокета

function ProcessSockEvents(Parameter: Pointer): Integer;

var

 S: TSocket;

 NetworkEvents: TWSANetworkEvents;

begin

 // Так как типы TSocket и Pointer занимают по 4 байта, такое

 // приведение типов вполне возможно, хотя и некрасиво

 S := TSocket(Parameter);

 // Связываем событие SockEvents[0] с FD_READ и FD_CLOSE

 WSAEventSelect(S, SockEvents[0], FD_READ or FD_CLOSE);

 while True do

 begin

case WSAWaitForMultipleEvents(3, @SockEvents[0], True, WSA_INFINITE, False) of

WSA_WAIT_EVENT_0: begin

WSAEnumNetworkEvents(S, SockEvents[0], NetworkEvents);

if NetworkEvents.lNetworkEvents and FD_READ > 0 then

if NetworkEvents.iErrorCode[FD_READ_BIT] = 0 then

begin

// Пришли данные, которые нужно прочитать

end

else

begin

// произошла ошибка. Нужно сообщить о ней и завершить нить

closesocket(3);

Exit;

end;

if NetworkEvents.lNetworkEvents and FD_CLOSE > 0 then

begin

// Связь разорвана

if NetworkEvents.iErrorCode[FD_CLOSE_BIT] = 0 then begin

// Связь закрыта корректно

end

else

begin

// Связь разорвана в результате сбоя сети

end;

// В любом случае нужно закрыть сокет и завершить нить

closesocket(S);

Exit;

end;

end;

WSA_WAIT_EVENT_0 + 1: begin

// Получен сигнал о необходимости отправить данные

// Здесь должен быть код отправки данных

// После отправки событие нужно сбросить вручную

ResetEvent(SockEvents[1]);

end;

WSA_WAIT_EVENT_0 + 2: begin

// Получен сигнал о необходимости завершения работы нити

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

Неудержимый. Книга VIII

Боярский Андрей
8. Неудержимый
Фантастика:
фэнтези
попаданцы
аниме
6.00
рейтинг книги
Неудержимый. Книга VIII

Законы Рода. Том 6

Flow Ascold
6. Граф Берестьев
Фантастика:
юмористическое фэнтези
аниме
5.00
рейтинг книги
Законы Рода. Том 6

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

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

Попаданка

Ахминеева Нина
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Попаданка

Возлюби болезнь свою

Синельников Валерий Владимирович
Научно-образовательная:
психология
7.71
рейтинг книги
Возлюби болезнь свою

Кодекс Крови. Книга III

Борзых М.
3. РОС: Кодекс Крови
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Крови. Книга III

Ротмистр Гордеев 2

Дашко Дмитрий
2. Ротмистр Гордеев
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Ротмистр Гордеев 2

Идеальный мир для Лекаря 5

Сапфир Олег
5. Лекарь
Фантастика:
фэнтези
юмористическая фантастика
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 5

Адвокат Империи 3

Карелин Сергей Витальевич
3. Адвокат империи
Фантастика:
городское фэнтези
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Адвокат Империи 3

Жребий некроманта 3

Решетов Евгений Валерьевич
3. Жребий некроманта
Фантастика:
боевая фантастика
5.56
рейтинг книги
Жребий некроманта 3

Город драконов

Звездная Елена
1. Город драконов
Фантастика:
фэнтези
6.80
рейтинг книги
Город драконов

Убивать, чтобы жить

Бор Жорж
1. УЧЖ
Фантастика:
героическая фантастика
боевая фантастика
рпг
5.00
рейтинг книги
Убивать, чтобы жить

Инквизитор Тьмы 2

Шмаков Алексей Семенович
2. Инквизитор Тьмы
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Инквизитор Тьмы 2

Беглец

Бубела Олег Николаевич
1. Совсем не герой
Фантастика:
фэнтези
попаданцы
8.94
рейтинг книги
Беглец