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

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

Жанры

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

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

Шрифт:

// ***** Описание на C++ *****

DWORD WSAWaitForMultipleEvents(DWORD cEvents, const WSAEVENT FAR *lphEvents, BOOL fWaitAll, WORD dwTimeout, BOOL fAlertable);

// ***** Описание на Delphi *****

function WSAWaitForMultipleEvents(cEvents: DWORD; lphEvents: PWSAEvent; fWaitAll: BOOL; dwTimeout: DWORD; fAlertable: BOOL): DWORD;

Дескрипторы событий, взведения которых ожидает нить, должны храниться в массиве, размер которого передаётся через параметр

cEvents
, а указатель — через параметр
lphEvents
. Параметр
fWaitAll
определяет, что является условием окончания ожидания: если он равен
True
, ожидание завершается, когда все события из переданного массива оказываются во взведенном состоянии,
если
False
— когда оказывается взведенным хотя бы одно из них. Параметр
dwTimeout
определяет тайм-аут ожидания в миллисекундах. В WinSock 2 определена константа
WSA_INFINITE
(совпадающая по значению со стандартно константой
INFINITE
), которая задает бесконечное ожидание. Параметр
fAlertable
нужен при перекрытом вводе-выводе: мы рассмотрим его позже в разд. 2.2.9. Если перекрытый ввод-вывод не используется,
fAlertable
должен быть равен
False
.

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

WSA_MAXIMUM_WAIT_EVENTS
, которая в данной реализации равна 64.

Результат, возвращаемый функцией, позволяет определить, по каким причинам закончилось ожидание. Если ожидалось взведение всех событий (

fWaitAll = True
), и оно произошло, функция возвращает
WSA_WAIT_EVENT_0
(0). Если ожидалось взведение хотя бы одного из событий, возвращается
WSA_WAIT_EVENT_0 + Index
, где
Index
— индекс взведенного события в массиве
lphEvents
(отсчет индексов начинается с нуля). Если ожидание завершилось по тайм-ауту, возвращается значение
WSA_WAIT_TIMEOUT
(258). И наконец, если произошла какая-либо ошибка, функция возвращает
WSA_WAIT_FAILED
(
$FFFFFFFF
).

Существует еще одно значение, которое может возвратить функция

WSAWaitForMultipleEvents
:
WAIT_IO_COMPLETION
(это константа из стандартной части Windows API, она объявлена в модуле
Windows
). Смысл этого результата и условия, при которых он может быть возвращен, мы рассмотрим в разд. 2.2.9.

Функции, которые мы рассматривали до сих пор, являются аналогами системных функций для стандартных событий. Теперь мы переходим к рассмотрению тех функций, которые отличают сокетные события от стандартных. Главная из них —

WSAEventSelect
, позволяющая привязать события, создаваемые с помощью
WSACreateEvent
, к тем событиям, которые происходят на сокете. Прототип этой функции приведен в листинге 2.59.

Листинг 2.59. Функция
WSAEventSelect

// ***** Описание на C++ *****

int WSAEventSelect(SOCKET s, WSAEVENT hEventObject, long lNetworkEvents);

// ***** описание на Delphi *****

function WSAEventSelect(S: TSocket; hEventObject: TWSAEvent; lNetworkEvents: LongInt): Integer;

Эта функция очень похожа на функцию

WSAAsyncSelect
, за исключением того, что события
FD_XXX
привязываются не к оконным сообщениям, а к сокетным событиям. Параметр
S
определяет сокет, события которого отслеживаются, параметр
hEventObject
— событие, которое должно взводиться при наступлении отслеживаемых событий,
lNetworkEvents
— комбинация констант
FD_XXX
, определяющая, с какими событиями на сокете связывается событие
hSocketEvent
.

Функция

WSAEventSelect
возвращает ноль, если операция прошла успешно, и
SOCKET_ERROR
при возникновении ошибки.

Событие, связанное с сокетом функцией

WSAEventSelect
, взводится при тех же условиях, при которых в очередь окна помещается сообщение при использовании
WSAAsyncSelect
. Так, например, функция
recv
взводит событие, если после ее вызова в буфере сокета еще остаются данные. Но, с другой стороны, функция
recv
не сбрасывает событие, если данных в буфере сокета нет. А поскольку сокетные события не сбрасываются автоматически функцией
WSAWaitForMultipleEvents
, программа всегда должна сбрасывать события сама. Так, при обработке
FD_READ
наиболее типична ситуация, когда сначала сбрасывается событие, а потом вызывается функция
recv
, которая при необходимости снова взводит событие. Здесь мы снова имеем проблему ложных срабатываний в тех случаях, когда данные извлекаются из буфера по частям с помощью нескольких вызовов
recv
, но в данном случае проблему решить легче: не нужно отменять регистрацию событий, достаточно просто сбросить событие непосредственно перед последним вызовом
recv
.

В принципе, события

FD_XXX
разных сокетов можно привязать к одному сокетному событию, но этой возможностью обычно не пользуются, т.к. в WinSock2 отсутствуют средства, позволяющие определить, событие на каком из сокетов привело к взведению сокетного события. Поэтому приходится для каждого сокета создавать отдельное событие.

Как и в случае с

WSAAsyncSelect
при вызове
WSAEventSelect
сокет переводится в неблокирующий режим. Повторный вызов
WSAEventSelect
для данного сокета отменяет результаты предыдущего вызова (т.е. невозможно связать разные события
FD_XXX
одного сокета с разными сокетными событиями). Сокет, созданный в результате вызова accept или
WSAAccept
наследует связь с сокетными событиями, установленную для слушающего сокета.

Существует весьма важное различие между использованием оконных сообщений и сокетных событий для оповещения о том, что происходит на сокете.

Предположим, с помощью функции

WSAAsyncSelect
события
FD_READ
,
FD_WRITE
и
FD_CONNECT
связаны с некоторым оконным сообщением. Пусть происходит событие
FD_CONNECT
. В очередь окна помещается соответствующее сообщение. Затем, до того, как предыдущее сообщение будет обработано, происходит
FD_WRITE
. В очередь окна помещается еще одно сообщение, которое информирует об этом. И наконец, при возникновении
FD_READ
в очередь будет помещено третье сообщение. Затем оконная процедура получит их по очереди и обработает.

Теперь рассмотрим ситуацию, когда те же события связаны с сокетным событием. Когда происходит

FD_CONNECT
, сокетное событие взводится. Теперь если
FD_WRITE
и
FD_READ
произойдут до того, как сокетное событие будет сброшено, оно уже не изменит своего состояния. Таким образом, программа, работающая с асинхронными сокетами, основанными на событиях, должна, во-первых, учитывать, что взведенное событие может означать несколько событий
FD_XXX
, а во-вторых, иметь возможность узнать, какие именно события произошли с момента последней проверки. Для получения этой информации предусмотрена функция
WSAEnumNetworkEvents
, прототип которой приведен в листинге 2.60.

Листинг 2.60. Функция
WSAEnumNetworkEvents

// ***** Описание на C++ *****

int WSAEnumNetworkEvents(SOCKET s, WSAEVENT hEventObject, LPWSANETWORKEVENTS lpNetworkEvents);

// ***** Описание на Delphi *****

function WSAEnumNetworkEvents(S: TSocket; hEventObject: TWSAEvent; var NetworkEvents: TWSANetworkEvents): Integer;

Функция

WSAEnumNetworkEvents
через параметр
NetworkEvents
возвращает информацию о том, какие события произошли на сокете S с момента последнего вызова этой функции для данного сокета (или с момента запуска программы, если функция вызывается в первый раз). Параметр
hEventObject
необязательный, он определяет сокетное событие, которое нужно сбросить. Использование этого параметра позволяет обойтись без явного вызова функции
WSAResetEvent
для сброса события. Как и большинство функций WinSock, функция
WSAEnumNetworkEvents
возвращает ноль в случае успеха и ненулевое значение при возникновении ошибки.

Запись

TWSANetworkEvents
содержит информацию о произошедших событиях об ошибках (листинг 2.61).

Листинг 2.61. Тип
TWSANetworkEvents

// ***** Описание на C++ *****

typedef struct _WSANETWORKEVENTS {

 long lNetworkEvents;

 int iErrorCode[FD_MAX_EVENTS];

} WSANETWORKEVENTS, *LPWSANETWORKEVENTS;

// ***** Описание на Delphi *****

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

Неудержимый. Книга 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
рейтинг книги
Беглец