Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
Межпрограммное взаимодействие
Часто возникает необходимость организовать взаимодействие программ, написанных разными людьми или даже разными фирмами. Задача решается в рамках идеологии «клиент-сервер», когда одно приложение должно реагировать на запросы других приложений. Наконец, с развитием сетей совершенно обычной стала задача взаимодействия приложения на разных машинах. Для организации взаимодействия между задачами существует очень много инструментов. Некоторые из них позволяют работать в рамках только одной машины, некоторые - в рамках локальной или глобальной сети. Связь между двумя программами можно установить таким образом, что изменения в одном приложении будут отражаться во втором. Например, если Вы меняете число в электронной таблице, то во втором приложении данные обновятся автоматически и отобразят изменения. Кроме того, можно из своего приложения управлять другими приложениями такими, как Word for Windows, Excel и др. Dynamic Data Exchange (DDE) DDE дает возможность перейти через рамки приложения и взаимодействовать с другими приложениями и системами Windows. Dynamic Data Exchange получило свое имя потому, что позволяет двум приложениям обмениваться данными (текстовыми, через глобальную память) динамически во время выполнения. DDE - давний и прижившийся протокол обмена данными, появившийся еще на заре эры Windows. Ниша, занимаемая DDE - это оперативная передача и синхронизация данных в приложениях. Приложения, использующие DDE, подразделяются на две категории: клиенты и серверы. Оба участника процесса совершают контакты (conversations) по определенным темам (topics), при этом в рамках темы производится обмен элементами данных (items). Устанавливает контакт DDE-клиент, который посылает запрос, содержащий имена контакта и темы. После установления контакта всякое изменение элемента данных на DDE-сервере передается элементу данных клиента. Одно и то-же приложение может быть одновременно и сервером, и клиентом (например, MicroSoft Word). DDE-серверы Для построения DDE-сервера в Delphi имеются два объекта, расположенные на странице System Палитры Компонент - TDdeServerConv и TDdeServerItem. Обычно в проекте используется один объект TDdeServerConv и один или более TDdeServerItem. Для получения доступа к сервису DDE-сервера, клиенту потребуется знать несколько параметров: имя сервиса (Service Name) - это имя приложения (обычно - имя выполняемого файла без расширения EXE, возможно с полным путем); Topic Name - в название темы; Item Name – название элемента данных. Назначение объекта TDdeServerConv - общее управление DDE и обработка запросов от клиентов на выполнение макроса. Последнее выполняется в обработчике события OnExecuteMacro, например, как это сделано ниже: Важнейшим свойством компонента TDdeServerConv является название темы, содержащееся в свойстве Name. Клиент должен знать это имя при установлении контакта, за исключением случая, когда он подключается к данным контакта, скопированным в буфер обмена. В моменты открытия и закрытия контакта возникают события: Объект TDdeServerItem связывается с TDdeServerConv посредством свойства и определяет, что, собственно, будет пересылаться по DDE. В принципе, потокол DDE подразумевает обмен любыми данными, формат которых зарегистрирован в системе для передачи через буфер обмена. Однако для рассматриваемых компонентов эти возможности ограничиваются только текстовыми данными. Для этого у компонента TDdeServerItem есть свойства Text и Lines (Text имеет то же значение, что и Lines[0]). При изменении значения этих свойств автоматически происходит пересылка обновленных данных во все приложения-клиенты, установившие связь с сервером. Данный компонент позволяет также осуществлять установление связи через буфер обмена (Clipboard). Для этого служит метод CopyToClipboard. Необходимая информации помещается в через буфер обмена и может быть вызвана из приложения-клиента при установлении связи. Обычно, в DDE-серверах для этого есть специальный пункт меню Paste Special или Paste Link. DDE-клиенты Для построения DDE-клиента в Delphi используются два компонента TDDEClientConv и TDDEClientItem. Аналогично серверу, в программе обычно используется один объект TDDEClientConv и один и более связанных с ним TDDEClientItem. TDDEClientConv служит для установления связи с сервером и общим управлением DDE-связью. Установить связь с DDE-сервером можно как во время разработки, так и во время выполнения программы, причем двумя способами. Первый способ - заполнить вручную необходимые свойства компонента. Это DdeService, DdeTopic и ServiceApplication. Если во время разработки дважды щелкнуть на одном из первых двух свойств в Инспекторе Объектов - появится диалог для определения DDE-связи. Для установления связи через Clipboard в диалоге есть специальная кнопка Past Link. Ей можно воспользоваться, если Вы запустили DDE-сервер, сохранили каким-то образом информацию о связи и вошли в этот диалог. Например, если DDE-сервером является DataBase Desktop, то нужно загрузить в него какую-нибудь таблицу Paradox, выбрать любое поле и выбрать пункт меню Edit|Copy. Свойство ServiceApplication заполняется в том случае, если в поле DDEService содержится имя, отличное от имени программы, либо если эта программа не находится в текущей директории. В этом поле указывается полный путь и имя программы без расширения (.EXE). Данная информация нужна для автоматического запуска сервера при установлении связи по DDE, если тот еще не был запущен. Имена сервера DDE и темы содержатся в свойствах: Способ вхождения в контакт определяется свойством Метод Ниже приведен пример процедуры, осуществляющей связь с сервером. После того, как установлена связь, нужно позаботиться о поступающих по DDE данных, это делается в обработчике события OnChange объекта TDdeClietItem: Это единственная задача объекта TDdeClientItem. Свойство Property DDEConv: TddeClientConv Этого компонента предназначено для связи с соответствующим объектом DdeClientConv. А свойство Property DDEItem: string; Должно содержать имя элемента данных. Свойства Аналогичны соответствующим свойствам tDDEServerItem и содержат данные. На объект TDdeClientConv возлагаются еще две задачи: пересылка данных на сервер и выполнение макросов. Для этого у данного объекта есть соответствующие методы. Обмен сообщениями Как уже упоминалось ранее, операционная система Windows® основана на сообщениях, возникающих в результате действий пользователя, аппаратуры компьютера или других программ. Поведение каждого окна полностью определяется тем, какие оно принимает сообщения и как их обрабатывает. В большинстве случаев, обработка сообщений в Delphi выполняется через события. Однако, бывают ситуации, когда может потребоваться послать и/или обработать сообщение самостоятельно. Существуют два типа сообщений, которые могут потребовать обработки в обход обычной системы сообщений Delphi: В принципе, сообщения делятся на две категории: Командные сообщения используются как программистами, тек и Windows®. Они управляют элементам операционной системы и прикладным программам. Уведомляющие сообщения содержат информацию об изменении состояния окон Windows®, их отдельных элементов и устройств системы. Они посылаются только самой средой окон Windows®. Каждое сообщение имеет два параметра: WPARAM и LPARAM. В 32-х битной среде оба эти параметра имеют размер 32 бита (longword). В 16-битной Windows WPARAM - это 16 битное число (word), а LPARAM - 32-битное (longint). Для отправки сообщений API Windows® содержит две функции: Первая из них отправляет сообщение в очередь сообщений Windows® и немедленно возвращает управление. PostMessage возвращает TRUE, если вызов функции прошел успешно и FALSE в противном случае. Функция SendMessage отличается от PostMessage тем, что, послав сообщение, она не возвратит управление до тех пор, пока сообщение не будет доведено до получателя. Обе функции имеют одинаковые параметры: HWND - дескриптор окна, которому предназначается сообщение, UINT - сообщение, которое должно быть послано, WPARAM и LPARAM - параметры сообщения. В следующем примере главной форме проекта посылается сообщение о закрытии приложения: В дополнение к функциям API Windows® VCL содержит метод Perform, который можно использовать для посылки сообщений любому окну VCL. Perform обходит систему передачи сообщений Windows® и направляет сообщение непосредственно механизму обработки данного окна. С использованием предыдущий пример будет выглядеть следующим образом: VCL имеет события примерно лишь для 20% наиболее часто используемых сообщений Windows®. У программиста может возникнуть необходимость обработать сообщения, для которых в VCL события не предусмотрены. Для обработки сообщений ОС, не имеющих соответствующих событий в Delphi есть ключевое слово message. С его помощью конкретный метод в коде программы может быть связан с любым сообщением Windows®. Когда окно приложения получает это сообщение вызывается соответствующий метод. Для реализации обработки сообщения на этом уровне необходимо: 1. Включить объявление метода для обработки сообщения в объявление класса, указав ключевое слово message и название сообщения, для обработки которого данный метод редназначен. 2. Включить определение метода в раздел implementation. Приведем пример определения метода, обрабатывающего сообщение WM_ERASEBKGND: Ключевое слово message указывает на то, что данный метод используется для обработки сообщения ОС, имя которого указано после этого ключевого слова: WM_ERASEBKGND. Следует также отметить, что параметр метода является записью типа tWMEraseBkgnd. В VCL имеются записи для большинства сообщений Windows® (они определены в модуле Messages.pas). Именем записи является имя сообщения с префиксом t и без подчеркивания. Сам метод можно назвать как угодно, но приведенная выше форма является общепринятой. В этом методе может возникнуть необходимость вызвать обработчик сообщения, установленный по умолчанию. Для этого необходимо вызвать виртуальный метод класса tObject DefaultHandler: Помимо нормальных сообщений Windows®, можно создать свое собственное сообщение. еализация и перехват определяемого пользователем сообщения идентичны обработке сообщений Windows®. Единственное отличие состоит в том, что это сообщение необходимо сначала определить: Эта строка объявляет пользовательское сообщение с именем My_Message. Для обработки сообщений, определенных пользователем в качестве типа параметра обработчика сообщения следует использовать запись общего вида tMessage: Здесь, как и во всех других определенных в 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 сокетов. И у того, и у другого имеется свойство: у компонента TClientSocket и у компонента TServerSocket Это свойство представляет собой объект — собственно оболочку сокета, со всеми функциями поддержки установления соединения, чтения и записи. азделение труда между ними такое—на уровне TServerSocket (TClientSocket) сосредоточены основные опубликованные свойства и события, обработку которых можно запрограммировать; на уровне TServerWinSocket (TClientWinSocket) следует искать функции, в том числе чтения и записи в сокет. Объект TServerWinSocket На уровне этого объекта ведется список соединений с клиентскими сокетами, содержащийся в свойстве: Общее число соединений (и число элементов в свойстве connections) равно значению свойства: Этим списком и счетчиком удобно пользоваться для рассылки всем клиентам какой-нибудь широковещательной информации, например: Тип сервера (блокирующий/неблокирующий) задается свойством Поскольку сервер, который блокируется каждым чтением/записью, представить себе трудно, разработчики фирмы Inprise пошли таким путем. Блокирующий режим заменен режимом stThreadBlocking. В этом случае при установлении каждого нового соединения запускается отдельный программный поток3 (объект класса TServerclientThread). Он отвечает за связь с отдельным клиентом, и его блокировка не влияет на работу остальных соединений. Если вы не хотите порождать TServerclientThread, а хотите описать свой класс потока и использовать его для работы с сокетом, вам нужно создать обработчик события: В отличие от stThreadBlocking, тип stNonBlocking своим поведением ничем не отличается от описанного выше — операции происходят асинхронно, и программист должен лишь описать реакцию на события, возникающие в момент их окончания. Как известно, создание и уничтожение нового программного потока влечет за собой определенные системные накладные расходы. Чтобы избежать этого, в рассматриваемом объекте ведется кэш потоков. По завершении соединения потоки не уничтожаются, а переводятся в состояние ожидания нового соединения. Свойство: property ThreadCacheSize: Integer; задает количество свободных потоков, которые могут находиться в готовности для установления соединения с клиентом. Это количество должно рассчитываться в зависимости от интенсивности и продолжительности контакта с клиентами. Лишние потоки поглощают системные ресурсы, в первую очередь память и процессорное время. Чтобы оптимизировать использование кэша свободных потоков, полезно поинтересоваться значением двух свойств: показывающих число активных (занятых обслуживанием клиентов) и простаивающих (ожидающих) потоков соответственно. Старт и завершение потока, работающего с сокетом, обрамлены событиями: Чтобы избежать ситуаций тупиков или гонок при работе с сокетами, имеются два метода: Если вами предусмотрен код, который может вызвать проблемы в многозадачной среде, заключите его между вызовами методов Lock и unlock — на это время остальные потоки, работающие с сокетами, будут блокированы. Методы чтения и записи для блокирующего и неблокирующего режима существенно отличаются. ассмотрим сначала те, что предназначены для неблокирующего (асинхронного) режима. Средства для организации чтения представлены группой из трех методов: возвращает число байт, которые могут быть приняты в ответ на оповещение клиента о передаче возвращает прочитанную из сокета текстовую строку возвращает данные, прочитанные из сокета в буфер Buf, в количестве count байт Аналогично, методы: function SendBuf(var Buf; Count: Integer): Integer; procedure SendText(const S: string); function SendStream (AStream: TStream): Boolean; посылают клиенту буфер, текстовую строку и поток данных. В дополнение к этому метод: function SendStrearoThenDrop (AStream: TStream): Boolean; посылает клиенту поток данных и завершает соединение. Передаваемый в качестве параметра последних двух функций поток данных AStream переходит " под надзор" объекта TServerWinsocket и удаляется им по мере пересылки. Программист не должен предпринимать попыток удалить AStream после вызова методов SendSrteam или SendSrteamThenDrop. При помощи метода: function GetClientThread(ClientSocket: TServerClientWinSocket): TServerClientThread; можно получить указатель на поток, занимающийся обслуживанием конкретного сокета. События: имеют одинаковый тип: Они происходят при соединении/отключении от клиента, а также при чтении и записи. Если произошла ошибка, возникает событие: Параметры его имеют следующее назначение. ErrorEvent указывает на тип операции, во время которой произошла ошибка. При этом ErrorCode содержит код ошибки Windows. Если вы сами обработали ошибку и не хотите дальнейших действий по ее обработке со стороны системы, нужно установить параметр ErrorCode в 0. Компонент TServerSocket Самое главное свойство этого компонента — уже упоминавшаяся ссылка на объект: Именно через него доступны все функциональные возможности сокета. Компонент же создан только для того, чтобы опубликовать необходимые свойства и события. В нем имеются свои события OnclientConnect, OnClientDisconnect, OnClientRead, OnClientWrite, OnClientError, но они не самостоятельны, а только отсылают к соответствующим событиям объекта TServerWinSocket. Также обстоит дело и со свойствами serverType и ThreadCacheSize. Дополнительно в компоненте предусмотрены события: происходит после того, как заданы адрес и порт сокета и перед тем, как он включается в режим прослушивания (готовности к соединению) происходит непосредственно после установки соединения Свойство property Active: Boolean; Свойство property Service: string; Объект TClientWinSocket Многие из событий и методов этого объекта уже описаны выше (см. объект TServerwinSocket), так как они имеют общего предка. Но есть и различия, требующие комментария. Как и серверный, клиентский сокет может быть двух типов: В отличие от сервера, в блокировке клиента большой беды нет. Если установлен режим ctBlocking, клиентское приложение блокируется до завершения операции. В режиме ctNonBiocking операции выполняются асинхронно. Компонент TClientSocket Основное внимание при рассмотрении этого компонента обратим на логику событий, происходящих при подключении клиентского сокета к серверу. Она такова: 1. Вызывается метод open (или свойство Active устанавливается в True). 2. Перед началом инициализации происходит событие В этот момент еще можно поменять свойства объекта TClieniwinSocket: адрес, номер порта и т. п. 3. Сокет полностью инициализируется и начинает поиск. Когда серверный сокет обнаружен, происходит событие 4. Когда клиентский запрос удовлетворен сервером и установлено соединение, происходит событие Проиллюстрируем сказанное на примере пересылки информации о дате и времени. Процесс подключения к серверу выглядит таким образом: После установления соединения клиент реагирует на событие onClientRead: В серверном приложении сокет устанавливается в активное состояние (прослушивание) при запуске программы. Все подключившиеся клиенты автоматически заносятся как элемент списка (свойство connections). Саму информацию о дате и времени сервер рассылает по таймеру в виде отформатированных текстовых строк: Сервер может отреагировать на сообщение от клиента. Ответ следует отправлять через параметр socket произошедшего события onClientRead: К сокетам проявляют интерес многие разработчики, что можно объяснить их универсальностью и широким распространением. Если вы не нашли чего-то для вас необходимого в компонентах TClientSocket и TServerSocket, или наоборот — сочли их слишком сложными в применении, вы можете использовать компонент TPowersock, разработанный компанией NetMasters. Он находится также на странице Internet Панели инструментов. |
Последнее изменение этой страницы: 2019-10-03; Просмотров: 235; Нарушение авторского права страницы