А. Григорьев - О чём не пишут в книгах по Delphi
- Название:О чём не пишут в книгах по Delphi
- Автор:
- Жанр:
- Издательство:БХВ-Петербург
- Год:2008
- Город:СПб
- ISBN:978-5-9775-019003
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
А. Григорьев - О чём не пишут в книгах по Delphi краткое содержание
Рассмотрены малоосвещённые вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные механизмы их работы, особенности для протоколов TCP и UDP и др. Большое внимание уделено разбору ситуаций возникновения ошибок и получения неверных результатов в "простом и правильном" коде. Отдельно рассмотрены особенности работы с целыми, вещественными и строковыми типами данных, а также приведены примеры неверных результатов, связанных с ошибками компилятора, VCL и др. Для каждой из таких ситуаций предложены методы решения проблемы. Подробно рассмотрен синтаксический анализ в Delphi на примере арифметических выражений. Многочисленные примеры составлены с учётом различных версий: от Delphi 3 до Delphi 2007. Прилагаемый компакт-диск содержит примеры из книги.
Для программистов
О чём не пишут в книгах по Delphi - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
Первые четыре параметра функции GetAcceptExSockAddrs
определяют буфер, в котором в результате вызова AcceptEx
оказались данные от клиента и адреса, и размеры частей буфера, зарезервированных для данных и для адресов. Значения этих параметров должны совпадать со значениями аналогичных параметров в соответствующем вызове AcceptEx
. Через параметр LocalSockaddrs
возвращается указатель на то место в буфере, в котором хранится адрес привязки сокета sAcceptSocket
, а через параметр LocalSockaddrsLength
— длина адреса (16 в случае TCP). Адрес клиента и его длина возвращаются через параметры RemoteSockaddrs
и RemoteSockaddrsLength
. Следует особенно подчеркнуть, что указатели LocalSockaddrs
и RemoteSockaddrs
указывают именно на соответствующие части буфера: память для них специально не выделяется и, следовательно, не должна освобождаться, а свою актуальность они теряют при освобождении буфера.
Последняя из дополнительных функций, TransmitFile
, служит для передачи файлов по сети. Ее прототип приведен в листинге 2.84.
TransmitFile
function TransmitFile(hSocket: TSocket; hFile: THandle; nNumberOfBytesToWrite, nNumberOfBytesPerSend: DWORD; lpOverlapped: POverlapped; lpTransmitBuffers: PTransmitFileBuffers; dwReserved: DWORD): BOOL;
Функция TransmitFile
отправляет содержимое указанного файла через указанный сокет. При этом допускаются только протоколы, поддерживающие соединение, т.е. использовать данную функцию с UDP-сокетом нельзя. Сокет задается параметром hSocket
, файл — параметром hFile
. Дескриптор файла обычно получается с помощью функции стандартного API CreateFile
. Файл рекомендуется открывать с флагом FILE_FLAG_SEQUENTIAL_SCAN
, т.к. это повышает производительность.
Параметр nNumberOfBytesToWrite
определяет, сколько байтов должно быть передано (позволяя, тем самым, передавать не весь файл, а только его часть). Если этот параметр равен нулю, передается весь файл.
Функция TransmitFile
кладет данные из файла в буфер сокета по частям. Параметр nNumberOfBytesPerSend
определяет размер одной порции данных. Он может быть равен нулю — в этом случае система сама определяет размер порции. Этот параметр критичен только в случае дейтаграммных протоколов, потому что при этом размер порции определяет размер дейтаграммы. Для TCP данные, хранящиеся в буфере, передаются в сеть целиком или по частям в зависимости от загрузки сети, готовности принимающей стороны и т.п., а какими порциями они попали в буфер, на размер пакета почти не влияет. Поэтому для TCP-сокета параметр nNumberOfBytesPerSend
лучше установить равным нулю.
Параметр lpOverlapped
указывает на запись TOverlapped
, использующуюся для перекрытого ввода-вывода. Эту структуру мы обсуждали при описании функции AcceptEx
. В отличие от AcceptEx
, в TransmitFile
этот параметр добыть равным nil
, и тогда операция передачи файла не будет перекрытой.
Если параметр lpOverlapped
равен nil
, передача файла начинается с той позиции, на которую указывает файловый указатель (для только что открытого файла этот указатель указывает на его начало, а переместить его можно, например, с помощью функции SetFilePointer
; также он перемещается при чтении файла с помощью ReadFile
). Если же параметр lpOverlapped
задан, то передача файла начинается с позиции, заданной значениями полей Offset
и OffsetHigh
, которые должны содержать соответственно младшую и старшую часть 64-битного смещения стартовой позиции от начала файла.
Параметр lpTransmitBuffers
является указателем на запись TTransmitFileBuffers
, объявленную так, как показано в листинге 2.85.
TTransmitFileBuffers
PTransmitFileBuffers = ^TTransmitFileBuffers;
_TRANSMIT_FILE_BUFFERS = record
Head: Pointer;
HeadLength: DWORD;
Tail: Pointer;
TailLength: DWORD;
end;
TTransmitFileBuffers = _TRANSMIT_FILE_BUFFERS;
С ее помощью можно указывать буферы, содержащие данные, которые должны быть отправлены перед передачей самого файла и после него. Поле Head
содержит указатель на буфер, содержащий данные, предназначенные для отправки перед файлом, HeadLength
— размер этих данных. Аналогично Tail
и TailLength
определяют начало и длину буфера с данными, которые передаются после передачи файла. Если передача дополнительных данных не нужна, параметр lpTransmitBuffer
может быть равен nil
.
Допускается и обратная ситуация: параметр hFile
может быть равен нулю, тогда передаются только данные, определяемые параметром lpTransmitBuffer
.
Последний параметр функции TransmitFile
в модуле WinSock
имеет имя Reserved
. В WinSock 1 он и в самом деле был зарезервирован и не имел смысла, но в WinSock 2 через него передаются флаги, управляющие операцией передачи файла. Мы не будем приводить здесь полный список возможных флагов (он есть в MSDN), а ограничимся лишь самыми важными. Указание флага TF_USE_DEFAULT_WORKER
или TF_USE_SYSTEM_THREAD
позволяет повысить производительность при передаче больших файлов, a TF_USE_KERNEL_APC
— при передаче маленьких файлов. Вообще, при работе с функцией TransmitFile
чтение файла и передачу данных в сеть осуществляет ядро операционной системы, что приводит к повышению быстродействия по сравнению с использованием ReadFile
и send
самой программой.
Функция TransmitFile
реализована по-разному в серверных версиях Windows NT/2000 и в остальных системах: в серверных версиях она оптимизирована по быстродействию, а в остальных — по количеству необходимых ресурсов.
Данные, переданные функцией TransmitFile
, удаленная сторона должна принимать обычным образом, с помощью функций recv/WSARecv
.
2.3. Итоги главы
На этом мы заканчиваем рассмотрение WinSock. Многие возможности этого стандарта остались не рассмотренными и даже не упомянутыми. Но для этого существуют книги, подобные [3]. Нашей же основной задачей было последовательное знакомство с базовыми возможностями WinSock API и способам их применения в Delphi.
Следует отметить, что в Delphi не обязательно напрямую использовать WinSock API, чтобы работать с сокетами, т.к. VCL содержит компоненты для этого. Прежде всего это TServerSocket
и TClientSocket
, использующие асинхронные сокеты, основанные на оконных сообщениях. Начиная с Delphi 7, к ним добавились компоненты TTCPServer
, TTCPClient
и TUDPSocket
, использующие блокирующие или неблокирующие сокеты. Кроме того, с Delphi поставляется библиотека Indy, которая тоже содержит компоненты для работы с сокетами. Но практика показывает, что освоить эти компоненты без знания особенностей WinSock API очень сложно, так что даже если вы никогда не будете вызывать функции WinSock API явно, а ограничитесь компонентами. информация, изложенная в этой главе, вам все равно пригодится.
Начиная с Delphi 7, компоненты TClientSocket
и TServerSocket
в поставке присутствуют, но в палитру компонентов по умолчанию не устанавливаются. Чтобы работать с этими компонентами, их нужно установить самостоятельно. Для этого в меню Componentследует выбрать пункт Install Packages, в открывшемся диалоговом окне нажать кнопку Addи добавить нужный пакет. Этот пакет находится в папке $(DELPHI)/Bin, а название его зависит от версии Delphi. Для Delphi 7 это будет dclsockets70.bpl, для BDS 2005 — dclsockets90.bpl, для BDS 2006, Turbo Delphi и Delphi 2007 — dclsockets100.bpl.
Интервал:
Закладка: