А. Григорьев - О чём не пишут в книгах по Delphi
- Название:О чём не пишут в книгах по Delphi
- Автор:
- Жанр:
- Издательство:БХВ-Петербург
- Год:2008
- Город:СПб
- ISBN:978-5-9775-019003
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
А. Григорьев - О чём не пишут в книгах по Delphi краткое содержание
Рассмотрены малоосвещённые вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные механизмы их работы, особенности для протоколов TCP и UDP и др. Большое внимание уделено разбору ситуаций возникновения ошибок и получения неверных результатов в "простом и правильном" коде. Отдельно рассмотрены особенности работы с целыми, вещественными и строковыми типами данных, а также приведены примеры неверных результатов, связанных с ошибками компилятора, VCL и др. Для каждой из таких ситуаций предложены методы решения проблемы. Подробно рассмотрен синтаксический анализ в Delphi на примере арифметических выражений. Многочисленные примеры составлены с учётом различных версий: от Delphi 3 до Delphi 2007. Прилагаемый компакт-диск содержит примеры из книги.
Для программистов
О чём не пишут в книгах по Delphi - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
Перекрытым вводом-выводом управляют два последних параметра функции, но 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).
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.
WSAGetOverlappedResult
// ***** Описание на C++ *****
BOOL WSAGetOverlappedResult(SOCKET s, LPWSAOVERLAPРED lpOverlapped, LPDWORD lpcbTransfer, BOOL fWait, LPDWORD lpdwFlags);
// ***** Описание на Delphi *****
function WSAGetOverlappedResult(S: TSocket; lpOverlapped: PWSAOverlapped; var cbTransfer: DWORD; fWait: BOOL; var Flags: DWORD): BOOL;
Параметры S
и lpOverlapped
функции WSAGetOverlappedResult
определяют coкет и операцию перекрытого ввода-вывода, информацию о которой требуется получить. Их значения должны совпадать со значениями соответствующих параметров, переданных функции WSARecv
. Через параметр cbTransfer
возвращается число полученных байтов, а через параметр Flags
— флаги (напомним, что в случае TCP и UDP флаги не модифицируются, и выходное значение параметра Flags
будет равно входному значению параметра Flags
функции WSARecv
).
Допускается вызов функции WSAGetOverlappedResult
до того, как операция перекрытого ввода-вывода будет завершена. В этом случае поведение функции зависит от параметра fWait
. Если он равен True
, функция переводит нить в состояние ожидания до тех пор, пока операция не будет завершена. Если он равен False
, функция завершается немедленно с ошибкой WSA_IO_INCOMPLETE
(996).
Функция WSAGetOverlappedResult
возвращает True
, если операция перекрытого ввода-вывода успешно завершена, и False
, если произошли какие-то ошибки. Ошибка может возникнуть в одном из трех случаев:
1. Операция перекрытого ввода-вывода еще не завершена, а параметр fWait
равен False
.
2. Операция перекрытого ввода-вывода завершилась с ошибкой (например, из-за разрыва связи).
3. Параметры, переданные функции WSAGetOverlappedResult
, имеют некорректные значения.
Точную причину, по которой функция вернула False
, можно установить стандартным образом — по коду ошибки, возвращаемому функцией WSAGetLastError
.
В принципе, программа может вообще не использовать события для отслеживания завершения операции ввода-вывода, а вызывать вместо этого время от времени функцию WSAGetOverlappedResult
в удобные для себя моменты. Тогда при вызове функции WSARecv
можно указать нулевое значение события hEvent
. Но следует иметь в виду, что при вызове функции WSAGetOverlappedResult
с параметром fWait
, равным True
, указанное событие служит для ожидания завершения операции, и если событие не задано, возникнет ошибка. Таким образом, если событие не используется, функция WSAGetOverlappedResult
не может вызываться в режиме ожидания.
Интервал:
Закладка: