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

на главную

Жанры

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

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

Шрифт:

При использовании перекрытого ввода-вывода операция, которая не может быть выполнена немедленно, формально завершается ошибкой — в этом заключается сходство перекрытого ввода-вывода и неблокирующего режима. Однако, в отличие от неблокирующего режима, при перекрытом вводе-выводе библиотека сокетов начинает выполнять операцию в фоновом режиме, после ее завершения начавшая операцию программа получает уведомление об успешно выполненной операции или о возникшей при ее выполнении фатальной ошибке. Несколько операций ввода-вывода могут одновременно выполняться в фоновом режиме, как бы перекрывая работу инициировавшей их нити и друг друга. Именно поэтому данная модель получила название модели перекрытого ввода-вывода.

Перекрытый ввод-вывод существовал и в спецификации WinSock 1, но реализовывался только

для линии NT. Специальных функций для перекрытого ввода-вывода в WinSock 1 не было, требовались функции
ReadFile
и
WriteFile
, в которые вместо дескриптора файла подставлялся дескриптор сокета. В WinSock 2 появилась полноценная поддержка перекрытого ввода-вывода для всех версий Windows, а в спецификацию добавились новые функции для его реализации, избавившие от необходимости использования функций файлового ввода-вывода. Здесь мы будем рассматривать перекрытый ввод-вывод только в спецификации WinSock 2, т.к. старый вариант из-за своих ограничений уже не имеет практического смысла.

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

WSAGetOverlappedResult
(ее мы рассмотрим позже).

Чтобы сокет мог использоваться в операциях перекрытого ввода-вывода, при его создании должен быть установлен флаг

WSA_FLAG_OVERLAPPED
(функция
socket
неявно устанавливает этот флаг). Для выполнения операций перекрытого ввода-вывода сокет не нужно переводить в какой-либо особый режим, достаточно обычные функции
send
и
recv
заменить на
WSARecv
и
WSASend
. Сначала мы рассмотрим функцию
WSARecv
, прототип которой приведен в листинге 2.68.

Листинг 2.68. Функция
WSARecv

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

int WSARecv(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);

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

function WSARecv(S: TSocket; lpBuffers: PWSABuf; dwBufferCount: DWORD; var NumberOfBytesRecvd: DWORD; var Flags: DWORD; lpOverlapped: PWSAOverlapped; lpCompletionRoutine: TWSAOverlappedCompletionRoutine): Integer;

Перекрытым вводом-выводом управляют два последних параметра функции, но

WSARecv
обладает и другими дополнительными по сравнению с функцией
recv
возможностями, не связанными с перекрытым вводом-выводом. Если оба этих параметра равны
nil
, или сокет создан без указания флага
WSA_FLAG_OVERLAPPED
, функция работает в обычном блокирующем или неблокирующем режиме, который установлен для сокета. При этом ее поведение отличается от поведения функции
recv
только тремя незначительными аспектами: во-первых, вместо одного буфера ей можно передать несколько, заполняемых последовательно. Во-вторых, флаги передаются ей не как значение, а как параметр-переменная, и при некоторых условиях функция
WSARecv
может их изменять (при использовании TCP и UDP флаги никогда не меняются, поэтому мы не будем рассматривать здесь эту возможность). В-третьих, при успешном завершении функция
WSARecv
возвращает ноль, а не число прочитанных байтов (последнее возвращается через параметр
lpNumberOfBytesRecvd
).

Буферы, в которые нужно поместить данные, передаются функции

WSARecv
через параметр
lpBuffers
. Он содержит указатель на начало массива структур
TWSABuf
, а параметр
dwBufferCount
— число элементов
в этом массиве. Ранее мы знакомились со структурой
TWSABuf
(см. листинг 2.39): она содержит указатель на начало буфера и его размер. Соответственно, массив таких структур определяет набор буферов. При чтении данных заполнение буферов начинается с первого буфера в массиве
lpBuffers
, затем, если в нем не хватает места, заполняется второй буфер и т.д. Функция не переходит к следующему буферу, пока не заполнит предыдущий до последнего байта. Таким образом, данные, получаемые с помощью функции
WSARecv
, могут быть помещены в несколько несвязных областей памяти, что иногда бывает удобно, если принимаемые сообщения имеют строго определенный формат с фиксированными размерами компонентов пакета: в этом случае можно каждый компонент поместить в свой независимый буфер.

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

WSARecv
параметр
lpCompletionRoutine
должен быть равен
nil
, а через параметр
lpOverlapped
передается указатель на запись
TWSAOverlapped
, которая определена следующим образом (листинг 2.69).

Листинг 2 69. Тип
TWSAOverlapped

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

struct _WSAOVERLAPPED {

 DWORD Internal;

 DWORD InternalHigh;

 DWORD Offset;

 DWORD OffsetHigh;

 WSAEVENT hEvent;

} WSAOVERLAPPED, *LPWSAOVEPLAPPED;

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

PWSAOverlapped = ^TWSAOverlapped;

TWSAOverlapped = packed record

 Internal, InternalHigh, Offer, OffsetHigh: DWORD;

 hEvent: TWSAEvent;

end;

Поля

Internal
,
InternalHigh
,
Offset
и
OffsetHigh
предназначены для внутреннего использования системой, программа не должна выполнять никаких действий с ними. Поле
hEvent
задает событие, которое будет взведено при завершении операции перекрытого ввода-вывода. Если на момент вызова функции
WSARecv
данные в буфере сокета отсутствуют, она вернет значение
SOCKET_ERROR
, а функция
WSAGetLastError
WSA_IO_PENDING
(997). Это значит, что операция начала выполняться в фоновом режиме. В этом случае функция
WSARecv
не изменяет значения параметров
NumberOfBytesRecvd
и
Flag
. Поля структуры
TWSAOverlapped
при этом также модифицируются, и эта структура должна быть сохранена программой в неприкосновенности до окончания операции перекрытого ввода-вывода. После окончания операции будет взведено событие, указанное в поле
hEvent
параметра
lpOverlapped
. При необходимости программа может дождаться этого взведения с помощью функции
WSAWaitForMultipleEvents
.

Как только запрос будет выполнен, в буферах, переданных через параметр

lpBuffers
, оказываются принятые данные. Но знания одного только факта, что запрос выполнен, недостаточно, чтобы этими данными воспользоваться, потому что, во-первых, неизвестен размер этих данных, а во-вторых, неизвестно, успешно ли завершена операция перекрытого ввода-вывода. Для получения недостающей информации служит функция
WSAGetOverlappedResult
, прототип которой приведен в листинге 2.70.

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

Измена. Я отомщу тебе, предатель

Вин Аманда
1. Измены
Любовные романы:
современные любовные романы
5.75
рейтинг книги
Измена. Я отомщу тебе, предатель

Сводный гад

Рам Янка
2. Самбисты
Любовные романы:
современные любовные романы
эро литература
5.00
рейтинг книги
Сводный гад

Мимик нового Мира 6

Северный Лис
5. Мимик!
Фантастика:
юмористическая фантастика
попаданцы
рпг
5.00
рейтинг книги
Мимик нового Мира 6

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

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

Начальник милиции

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

Магия чистых душ

Шах Ольга
Любовные романы:
любовно-фантастические романы
5.40
рейтинг книги
Магия чистых душ

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

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

Стрелок

Астахов Евгений Евгеньевич
5. Сопряжение
Фантастика:
боевая фантастика
постапокалипсис
рпг
5.00
рейтинг книги
Стрелок

На границе империй. Том 6

INDIGO
6. Фортуна дама переменчивая
Фантастика:
боевая фантастика
космическая фантастика
попаданцы
5.31
рейтинг книги
На границе империй. Том 6

Архил…? Книга 3

Кожевников Павел
3. Архил...?
Фантастика:
фэнтези
попаданцы
альтернативная история
7.00
рейтинг книги
Архил…? Книга 3

Доктора вызывали? или Трудовые будни попаданки

Марей Соня
Фантастика:
юмористическая фантастика
попаданцы
5.00
рейтинг книги
Доктора вызывали? или Трудовые будни попаданки

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

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

Черный Маг Императора 5

Герда Александр
5. Черный маг императора
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Черный Маг Императора 5

Последний попаданец 2

Зубов Константин
2. Последний попаданец
Фантастика:
юмористическая фантастика
попаданцы
рпг
7.50
рейтинг книги
Последний попаданец 2