Программирование на Delphi
выбрать пункт меню Edit|Copy. Свойство ServiceApplication заполняется в том
случае, если в поле DDEService содержится имя, отличное от имени программы,
либо если эта программа не находится в текущей директории. В этом поле
указывается полный путь и имя программы без расширения (.EXE). Данная
информация нужна для автоматического запуска сервера при установлении связи
по DDE, если тот еще не был запущен.
Имена сервера DDE и темы содержатся в свойствах:
Property DDEService:string;
Property DDETopic:string;
Способ вхождения в контакт определяется свойством
Property ConnectMode:tDataMode;
Type tDataMode = (DDEAutomatic,DDEManual);
Метод
Function SetLinc(const Service: string; const Topic: string):Boolean;
Присваивает свойствам DDEService и DDETopic соответствующие значения, а в
случае, если задан режим DDEAutomatic, и устанавливает контакт. В режиме
DDEManual для установления контакта необходимо дополнительно вызвать метод
Function OpenLink: Boolean;
Этот метод сначала закрывает предыдущий контакт, затем пытается связаться с
сервером DDEService на тему DDETopic. Если это не удается сразу,
предпринимается попытка загрузить приложение с именем, определенным в
свойстве:
Property ServiceApplication: string;
Можно связаться с сервером, поместившим данные в буфер обмена с помощью
метода
Function PasteLink: boolean;
Ниже приведен пример процедуры, осуществляющей связь с сервером.
procedure TMainForm.doNewLink(Sender: TObject);
begin
DdeClient.SetLink(AppName.Text, TopicNameEdit.Text);
DdeClientItem.DdeConv := DdeClient;
DdeClientItem.DdeItem := ItemName.Text;
end;
procedure TMainForm.doPasteLink(Sender: TObject);
var
Service, Topic, Item : String;
begin
if GetPasteLinkInfo (Service, Topic, Item) then begin
AppName.Text := Service;
TopicName.Text := Topic;
ItemName.Text := Item;
DdeClient.SetLink (Service, Topic);
DdeClientItem.DdeConv := DdeClient;
DdeClientItem.DdeItem := ItemName.Text;
end;
end;
После того, как установлена связь, нужно позаботиться о поступающих по DDE
данных, это делается в обработчике события OnChange объекта TDdeClietItem:
procedure TFormD.DdeClientItemChange(Sender: TObject);
begin
DdeDat.Lines := DdeClientItem.Lines;
end;
Это единственная задача объекта TDdeClientItem.
Свойство
Property DDEConv: TddeClientConv
Этого компонента предназначено для связи с соответствующим объектом
DdeClientConv. А свойство
Property DDEItem:string;
Должно содержать имя элемента данных.
Свойства
Property Text: string;
Property Lines: tStrings;
Аналогичны соответствующим свойствам tDDEServerItem и содержат данные.
На объект TDdeClientConv возлагаются еще две задачи: пересылка данных на
сервер и выполнение макросов. Для этого у данного объекта есть
соответствующие методы.
Function ExecuteMacroLines(Cmd:tStrings, WaitFlg:Boolean):Boolean;
Function PokeDataLines(const Item:string,Data:tStrings):Boolean;
Обмен сообщениями
Как уже упоминалось ранее, операционная система Windows® основана на
сообщениях, возникающих в результате действий пользователя, аппаратуры
компьютера или других программ. Поведение каждого окна полностью
определяется тем, какие оно принимает сообщения и как их обрабатывает. В
большинстве случаев, обработка сообщений в Delphi выполняется через
события. Однако, бывают ситуации, когда может потребоваться послать и/или
обработать сообщение самостоятельно. Существуют два типа сообщений, которые
могут потребовать обработки в обход обычной системы сообщений Delphi:
Сообщения Windows®, не обрабатываемые VCL
Сообщения, определяемые пользователем
В принципе, сообщения делятся на две категории:
Командные сообщения
Уведомляющие сообщения
Командные сообщения используются как программистами, тек и Windows®. Они
управляют элементам операционной системы и прикладным программам.
Уведомляющие сообщения содержат информацию об изменении состояния окон
Windows®, их отдельных элементов и устройств системы. Они посылаются только
самой средой окон Windows®.
Каждое сообщение имеет два параметра: WPARAM и LPARAM. В 32-х битной среде
оба эти параметра имеют размер 32 бита (longword). В 16-битной Windows
WPARAM - это 16 битное число (word), а LPARAM - 32-битное (longint).
Для отправки сообщений API Windows® содержит две функции:
function PostMessage( HWND hWnd, // handle of destination window
UINT Msg, // message to post
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
):BOOLEAN;
function SendMessage( HWND hWnd, // handle of destination window
UINT Msg, // message to send
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
): LRESULT;
Первая из них отправляет сообщение в очередь сообщений Windows® и
немедленно возвращает управление. PostMessage возвращает TRUE, если вызов
функции прошел успешно и FALSE в противном случае.
Функция SendMessage отличается от PostMessage тем, что, послав сообщение,
она не возвратит управление до тех пор, пока сообщение не будет доведено до
получателя.
Обе функции имеют одинаковые параметры: HWND - дескриптор окна, которому
предназначается сообщение, UINT - сообщение, которое должно быть послано,
WPARAM и LPARAM - параметры сообщения.
В следующем примере главной форме проекта посылается сообщение о закрытии
приложения:
PostMessage(Handle,WM_QUIT,0,0);
В дополнение к функциям API Windows® VCL содержит метод Perform, который
можно использовать для посылки сообщений любому окну VCL.
function Perform(Msg: Cardinal; WParam, LParam: Longint): Longint;
Perform обходит систему передачи сообщений Windows® и направляет сообщение
непосредственно механизму обработки данного окна. С использованием
предыдущий пример будет выглядеть следующим образом:
Perform(WM_QUIT,0,0);
VCL имеет события примерно лишь для 20% наиболее часто используемых
сообщений Windows®. У программиста может возникнуть необходимость
обработать сообщения, для которых в VCL события не предусмотрены. Для
обработки сообщений ОС, не имеющих соответствующих событий в Delphi есть
ключевое слово message. С его помощью конкретный метод в коде программы
может быть связан с любым сообщением Windows®. Когда окно приложения
получает это сообщение вызывается соответствующий метод. Для реализации
обработки сообщения на этом уровне необходимо:
1. Включить объявление метода для обработки сообщения в объявление класса,
указав ключевое слово message и название сообщения, для обработки которого
данный метод редназначен.
2. Включить определение метода в раздел implementation.
Приведем пример определения метода, обрабатывающего сообщение
WM_ERASEBKGND:
Procedure WmEraseBkgnd(var Msg:tWMEraseBkgnd); message WM_ERASEBKGND;
Ключевое слово message указывает на то, что данный метод используется для
обработки сообщения ОС, имя которого указано после этого ключевого слова:
WM_ERASEBKGND. Следует также отметить, что параметр метода является записью
типа tWMEraseBkgnd.
type TWMEraseBkgnd=record
Msg:Cardinal;
DC:HDC;
Unused:Longint;
Result:Longint;
end;
В VCL имеются записи для большинства сообщений Windows® (они определены в
модуле Messages.pas). Именем записи является имя сообщения с префиксом t и
без подчеркивания. Сам метод можно назвать как угодно, но приведенная выше
форма является общепринятой. В этом методе может возникнуть необходимость
вызвать обработчик сообщения, установленный по умолчанию. Для этого
необходимо вызвать виртуальный метод класса tObject DefaultHandler:
procedure tObject.DefaultHandler(var Message); virtual;
Помимо нормальных сообщений Windows®, можно создать свое собственное
сообщение. еализация и перехват определяемого пользователем сообщения
идентичны обработке сообщений Windows®. Единственное отличие состоит в том,
что это сообщение необходимо сначала определить:
Const My_Message = WM_USER + 1;
Эта строка объявляет пользовательское сообщение с именем My_Message.
Для обработки сообщений, определенных пользователем в качестве типа
параметра обработчика сообщения следует использовать запись общего вида
tMessage:
type tMessage = record
Msg:Cardinal;
WParam:Longint;
LParam:Longint;
Result:Longint;
end;
Здесь, как и во всех других определенных в VCL для сообщений записях, поле
Msg определяет передаваемое сообщение, поле Result - результат действия
обработчика. Уникальные для данной записи поля WParam и LParam содержат
соответствующие параметры сообщения.
Для посылки определяемых пользователем сообщений можно использовать функции
SendMessage, PostMessage, однако, предпочтительнее в данном случае
использовать Perform.
Сокеты
Наиболее современным и даже "модным" является общение процессов на уровне
сокетов. Популярность их обусловлена взрывным ростом интереса как
пользователей, так и специалистов к Internet и всему, что связано с этой
сетью.
Общепринятой и стандартизованной на международном уровне является
семиуровневая модель структуры протоколов связи под названием интерфейс
открытых систем (Open Systems Interface, OSI). На каждом из уровней — от
первого, физического, до высших уровней представления и приложений —
решается свой объем задач и используется свой инструментарий.
Сокеты находятся как раз на промежуточном, так называемом транспортном
уровне семиуровневой структуры. "Под ним", на сетевом уровне, находится
протокол IP (основа TCP/IP — Transmission Control Protocol/Internet
Protocol). Над ним находятся протоколы сеансового уровня (сервисы),
ориентированные на конкретные задачи — например, FTP (для передачи файлов),
SMTP (почтовый), всем известный гипертекстовый протокол HTTP и другие.
Использование сокетов, с одной стороны, позволяет абстрагироваться от
частностей работы на нижних уровнях, с другой — решать широкий круг задач,
недоступный специализированным протоколам.
С точки зрения своей сущности сокет — это модель одного конца сетевого
соединения, со своими свойствами и возможностью читать и записывать данные.
С точки зрения содержания — это прикладной программный интерфейс, входящий
в состав разных операционных систем, в том числе Windows — начиная с версии
3.11. Последняя его реализация носит название WinSock 2.0. Прототипы
функций содержатся в файле WINSOCK.PAS, поставляемом с Delphi.
API сокетов впервые появился в среде Unix и стал популярен вместе с (и
благодаря) протоколом TCP/IP. Именно они являются строительным материалом,
из которого построена сеть Internet. Но сокеты не обязательно базируются на
TCP/IP, они могут базироваться на IPX/SPX и других протоколах.
Механизм соединения при помощи сокетов таков. На одной стороне создается
клиентский сокет. Для инициализации связи ему нужно задать путь к
серверному сокету, с которым предстоит установить соединение.
Путь в сети задается двумя параметрами: адресом или равноценным ему именем
хоста, или просто хостом и номером порта. Хост — это система, в которой
запущено приложение, содержащее сокет. Неверно приравнивать понятие "хост"
или "адрес" к понятию "компьютер" — у компьютера может быть несколько
сетевых устройств и несколько адресов. Адрес в сетях TCP/IP задается
четверкой чисел в диапазоне 0..255, например, так: 192.168.99.1.
Естественно, каждый адрес даже в рамках Internet уникален — за этим следит
специальная организация. Имя хоста, как правило, — символьная строка,
поставленная в соответствие адресу и записанная по правилам UNC, например
http://www.microsoft.com. Взаимное соответствие между именами и адресами
может осуществляться по-разному, в зависимости от масштаба сети и
применяемой ОС. В Internet существует система имен доменов (DNS) —
специальные серверы, хранящие и поддерживающие таблицы соответствия между
символьным именем и адресом. Но в любом случае соединение по адресу
быстрее, так как не нужно обращаться за дополнительной информацией.
В случае, если ваши клиент/серверные приложения отлаживаются на одной и той
же машине, можно связать сокеты четырьмя способами:
. Указанием сетевого имени вашего компьютера (узнать его можно через
апплет "Сеть" Панели управления)
. Указанием IP — адреса вашего компьютера (узнать его можно в свойствах
протокола ТСР/IP: на машине должен стоять этот протокол и иметься
постоянный IP-адрес)
. Указанием имени localhost, указывающего, что сервер находится на том
же компьютере
. Указанием IP-адреса 127.0.0.1, указывающего на тоже самое
Номер порта — простое средство для поддержания одновременно нескольких
связей между двумя хостами. Это число, обычно зарезервированное для
протоколов более высокого уровня. Так, для протокола FTP выделен порт 21,
SMTP — 25, популярная игра Quake II использует порт 27910 и т. п.
Программист должен ознакомиться со списком уже закрепленных портов, прежде
чем установит и использует свое значение.
С одной из двух вступающих в связь сторон запускается серверный сокет.
Первоначально он находится в состоянии просушивания (listening), то есть
ожидания связи. После получения запроса от другой стороны — клиента —
устанавливается связь. Но в то же время создается новый сокет для
продолжения прослушивания.
Естественно, в составе Delphi имеется полноценная поддержка сокетов. Еще в
версии 2 появился заголовочный файл WINSOCK.PAS. Есть он и сейчас — для
желающих использовать API WinSock напрямую. Мы же рассмотрим здесь
компоненты TServerSocket и TClientSocket, имеющиеся в Delphi 4 на странице
Internet Палитры компонентов.
Очень важным моментом в использовании сокетов является задание их типа —
блокирующего (синхронного) и неблокирующего (асинхронного). По существу,
работа с сокетами — не что иное, как операции ввода/вывода, которые, как мы
знаем, также могут быть синхронными и асинхронными (отложенными). В первом
случае при вызове функции ввода/вывода приложение блокируется до его
окончания. Во втором — инициируется ввод/вывод и выполнение приложения
сразу же продолжается; окончание ввода/вывода будет "ознаменовано" в
системе возникновением некоторого события. В библиотеке WinSock 2.0
поддерживаются оба типа операций с сокетами; соответственно, в компонентах
Delphi также можно установить нужный тип. Отвечают за него свойства
serverType и clientType, о которых рассказано ниже.
Специфика компонентов TServerSocket и TClientSocket в том. что они являются
"двухэтажными" надстройками над API сокетов. И у того, и у другого имеется
свойство:
property Socket: TClientWinSocket;
у компонента TClientSocket и
property Socket: TServerWinSocket;
у компонента TServerSocket
Это свойство представляет собой объект — собственно оболочку сокета, со
всеми функциями поддержки установления соединения, чтения и записи.
азделение труда между ними такое—на уровне TServerSocket (TClientSocket)
сосредоточены основные опубликованные свойства и события, обработку которых
можно запрограммировать; на уровне TServerWinSocket (TClientWinSocket)
следует искать функции, в том числе чтения и записи в сокет.
Объект TServerWinSocket
На уровне этого объекта ведется список соединений с клиентскими сокетами,
содержащийся в свойстве:
property Connections [Index: Integer]: TCustomWinSocket;
Общее число соединений (и число элементов в свойстве connections) равно
значению свойства:
property ActiveConnections: Integer;
Этим списком и счетчиком удобно пользоваться для рассылки всем клиентам
какой-нибудь широковещательной информации, например:
for i:=0 to ServerSocket.Socket.ActiveConnections-1 do
ServerSocket.Socket.Connections[i].SendText('Hi! ');
Тип сервера (блокирующий/неблокирующий) задается свойством
type TServerType = (stNonBiocking, stThreadBiocking);
property ServerType: TServerType;
Поскольку сервер, который блокируется каждым чтением/записью, представить
себе трудно, разработчики фирмы Inprise пошли таким путем. Блокирующий
режим заменен режимом stThreadBlocking. В этом случае при установлении
каждого нового соединения запускается отдельный программный поток3 (объект
класса TServerclientThread). Он отвечает за связь с отдельным клиентом, и
его блокировка не влияет на работу остальных соединений.
Если вы не хотите порождать TServerclientThread, а хотите описать свой
класс потока и использовать его для работы с сокетом, вам нужно создать
обработчик события:
property OnGetThread: TGetThreadEvent;
type TGetThreadEvent = procedure (Sender: TObject;
ClientSocket: TServerClientWinSocket; var SocketThread:
TServerCiientThread) of object;
В отличие от stThreadBlocking, тип stNonBlocking своим поведением ничем не
отличается от описанного выше — операции происходят асинхронно, и
программист должен лишь описать реакцию на события, возникающие в момент их
окончания.
Как известно, создание и уничтожение нового программного потока влечет за
собой определенные системные накладные расходы. Чтобы избежать этого, в
рассматриваемом объекте ведется кэш потоков. По завершении соединения
потоки не уничтожаются, а переводятся в состояние ожидания нового
соединения.
Свойство: property ThreadCacheSize: Integer;
задает количество свободных потоков, которые могут находиться в готовности
Страницы: 1, 2, 3, 4, 5, 6, 7
|