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

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

Жанры

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

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

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

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

Мастер 7

Чащин Валерий
7. Мастер
Фантастика:
фэнтези
боевая фантастика
попаданцы
технофэнтези
аниме
5.00
рейтинг книги
Мастер 7

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

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

Все не случайно

Юнина Наталья
Любовные романы:
современные любовные романы
7.10
рейтинг книги
Все не случайно

Гром над Тверью

Машуков Тимур
1. Гром над миром
Фантастика:
боевая фантастика
5.89
рейтинг книги
Гром над Тверью

Идущий в тени 5

Амврелий Марк
5. Идущий в тени
Фантастика:
фэнтези
рпг
5.50
рейтинг книги
Идущий в тени 5

Кровь, золото и помидоры

Распопов Дмитрий Викторович
4. Венецианский купец
Фантастика:
альтернативная история
5.40
рейтинг книги
Кровь, золото и помидоры

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

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

Чужое наследие

Кораблев Родион
3. Другая сторона
Фантастика:
боевая фантастика
8.47
рейтинг книги
Чужое наследие

Пистоль и шпага

Дроздов Анатолий Федорович
2. Штуцер и тесак
Фантастика:
альтернативная история
8.28
рейтинг книги
Пистоль и шпага

Мастер 4

Чащин Валерий
4. Мастер
Фантастика:
героическая фантастика
боевая фантастика
попаданцы
5.00
рейтинг книги
Мастер 4

Темный Патриарх Светлого Рода 6

Лисицин Евгений
6. Темный Патриарх Светлого Рода
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Темный Патриарх Светлого Рода 6

Лорд Системы 14

Токсик Саша
14. Лорд Системы
Фантастика:
фэнтези
попаданцы
рпг
5.00
рейтинг книги
Лорд Системы 14

Падение Твердыни

Распопов Дмитрий Викторович
6. Венецианский купец
Фантастика:
попаданцы
альтернативная история
5.33
рейтинг книги
Падение Твердыни