Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Межпрограммное взаимодействие



Часто возникает необходимость организовать взаимодействие программ, написанных разными людьми или даже разными фирмами. Задача решается в рамках идеологии «клиент-сервер», когда одно приложение должно реагировать на запросы других приложений. Наконец, с развитием сетей совершенно обычной стала задача взаимодействия приложения на разных машинах.

Для организации взаимодействия между задачами существует очень много инструментов. Некоторые из них позволяют работать в рамках только одной машины, некоторые - в рамках локальной или глобальной сети. Связь между двумя программами можно установить таким образом, что изменения в одном приложении будут отражаться во втором. Например, если Вы меняете число в электронной таблице, то во втором приложении данные обновятся автоматически и отобразят изменения. Кроме того, можно из своего приложения управлять другими приложениями такими, как 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, например, как это сделано ниже:

procedure TDdeSrvrForm.DoMacro(Sender: TObject; Msg: TStrings);
var
Text: string;
Begin
Text: = '';
if Msg.Count > 0 then Text: = Msg.Strings[0];
MessageDlg ('Executing Macro - ' + Text, mtInformation, [mbOK], 0);
End;

Важнейшим свойством компонента TDdeServerConv является название темы, содержащееся в свойстве Name. Клиент должен знать это имя при установлении контакта, за исключением случая, когда он подключается к данным контакта, скопированным в буфер обмена.

В моменты открытия и закрытия контакта возникают события:

Property OnOpen: tNotifyEvent;
Property OnClose: tNotifyEvent;

Объект TDdeServerItem связывается с TDdeServerConv посредством свойства

Property ServerConv: tDDEServerConv,

и определяет, что, собственно, будет пересылаться по DDE. В принципе, потокол DDE подразумевает обмен любыми данными, формат которых зарегистрирован в системе для передачи через буфер обмена. Однако для рассматриваемых компонентов эти возможности ограничиваются только текстовыми данными. Для этого у компонента TDdeServerItem есть свойства Text и Lines (Text имеет то же значение, что и Lines[0]).

Property Text: string;
Property Lines: tStrings;

При изменении значения этих свойств автоматически происходит пересылка обновленных данных во все приложения-клиенты, установившие связь с сервером.

Данный компонент позволяет также осуществлять установление связи через буфер обмена (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 и темы содержатся в свойствах:

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;

задает количество свободных потоков, которые могут находиться в готовности для установления соединения с клиентом. Это количество должно рассчитываться в зависимости от интенсивности и продолжительности контакта с клиентами. Лишние потоки поглощают системные ресурсы, в первую очередь память и процессорное время. Чтобы оптимизировать использование кэша свободных потоков, полезно поинтересоваться значением двух свойств:

property ActiveThreads: Integer;

property IdieThreads: Integer;

показывающих число активных (занятых обслуживанием клиентов) и простаивающих (ожидающих) потоков соответственно.

Старт и завершение потока, работающего с сокетом, обрамлены событиями:

property OnThreadStart: TThreadNotifyEvent;
property OnThreadEnd: TThreadNotifyEvent;
type TTnreadNotifyEvent=procedure(Sender: TObject;
Thread: TServerClientThread) of object;

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

procedure Lock;
procedure Unlock;

Если вами предусмотрен код, который может вызвать проблемы в многозадачной среде, заключите его между вызовами методов Lock и unlock — на это время остальные потоки, работающие с сокетами, будут блокированы.

Методы чтения и записи для блокирующего и неблокирующего режима существенно отличаются. ассмотрим сначала те, что предназначены для неблокирующего (асинхронного) режима.

Средства для организации чтения представлены группой из трех методов:

function ReceiveLength: Integer;

возвращает число байт, которые могут быть приняты в ответ на оповещение клиента о передаче

function ReceiveText: string;

возвращает прочитанную из сокета текстовую строку

function ReceiveBuf(var Buf; Count: Integer): Integer;

возвращает данные, прочитанные из сокета в буфер 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;

можно получить указатель на поток, занимающийся обслуживанием конкретного сокета.

События:

property OnClientConnect;
property OnClientDisconnect;
property OnClientRead;
property OnClientWrite;

имеют одинаковый тип:

TSocketNotifyEvent=procedure(Sender: TObject;
Socket: TCustomWinSocket) of object;

Они происходят при соединении/отключении от клиента, а также при чтении и записи. Если произошла ошибка, возникает событие:

property OnClientError; TSocketErrorEvent;
type
TErrorEvent = (eeGeneral, eeSend, eeReceive, eeConnect, eeDisconnect, eeAccept);
TSocketErrorEvent = procedure (Sender: TObject;
Socket: TCustomWinSocket;
ErrorEvent: TErrorEvent;
var ErrorCode: Integer) of object;

Параметры его имеют следующее назначение. ErrorEvent указывает на тип операции, во время которой произошла ошибка. При этом ErrorCode содержит код ошибки Windows. Если вы сами обработали ошибку и не хотите дальнейших действий по ее обработке со стороны системы, нужно установить параметр ErrorCode в 0.

Компонент TServerSocket

Самое главное свойство этого компонента — уже упоминавшаяся ссылка на объект:

property Socket: TServerWinSocket;

Именно через него доступны все функциональные возможности сокета. Компонент же создан только для того, чтобы опубликовать необходимые свойства и события. В нем имеются свои события OnclientConnect, OnClientDisconnect, OnClientRead, OnClientWrite, OnClientError, но они не самостоятельны, а только отсылают к соответствующим событиям объекта TServerWinSocket. Также обстоит дело и со свойствами serverType и ThreadCacheSize.

Дополнительно в компоненте предусмотрены события:

property OnListen: TSocketNotifyEvent;

происходит после того, как заданы адрес и порт сокета и перед тем, как он включается в режим прослушивания (готовности к соединению)

property OnAccept: TSocketNotifyEvent;

происходит непосредственно после установки соединения

Свойство property Active: Boolean;
отвечает за состояние сокета. Для клиентского сокета изменение его значения соответствует подключению/отключению от сервера. Для серверного — включение/выключение состояния прослушивания. Использование этого свойства равносильно применению следующих методов:

procedure Open;

procedure Close;

Свойство property Service: string;
служит для идентификации предназначения сокета. Здесь должно храниться символьное имя сервиса, для которого используется сокет (ftp, http, telnet и др.)

Объект TClientWinSocket

Многие из событий и методов этого объекта уже описаны выше (см. объект TServerwinSocket), так как они имеют общего предка. Но есть и различия, требующие комментария. Как и серверный, клиентский сокет может быть двух типов:

type TCiientType = (ctNonBlocking, ctBlocking);
property ClientType: TCiientType;

В отличие от сервера, в блокировке клиента большой беды нет. Если установлен режим ctBlocking, клиентское приложение блокируется до завершения операции. В режиме ctNonBiocking операции выполняются асинхронно.

Компонент TClientSocket

Основное внимание при рассмотрении этого компонента обратим на логику событий, происходящих при подключении клиентского сокета к серверу. Она такова:

1. Вызывается метод open (или свойство Active устанавливается в True).

2. Перед началом инициализации происходит событие

property onLookup: TSocketNotifyEvent;.

В этот момент еще можно поменять свойства объекта TClieniwinSocket: адрес, номер порта и т. п.

3. Сокет полностью инициализируется и начинает поиск. Когда серверный сокет обнаружен, происходит событие

property onConneciing: TSocketNotifyEvent;.

4. Когда клиентский запрос удовлетворен сервером и установлено соединение, происходит событие

property OnConnect: TSocketNotifyEvent;

Проиллюстрируем сказанное на примере пересылки информации о дате и времени. Процесс подключения к серверу выглядит таким образом:

procedure TClientForm.FileConnectltemClick(Sender: TObject);
Begin
if ClientSocket.Active then ClientSocket.Active: = False;
if InputQuery('Сервер', 'Адрес (имя)', Server) then
if Length(Server)> 0 then
with ClientSocket do begin
Host: = Server;
Active: = True;
end;
End;

После установления соединения клиент реагирует на событие onClientRead:

procedure TCiientFom.ClientSocketRead(Sender: TObject; Socket: TCustomWinSocket);
var s: string;
Begin
s: = Socket.ReceiveText;
if ((s[l]='T') and (TimeSpeedButton.Down)) then
TimeSpeedButton.Caption: =Copy(s, 2, Length(s))
else if ((s[l]='M') and (MemSpeedButton. Down)) then
KemSpeedButton.Caption: =Copy(s, 2, Length (s));
End;

В серверном приложении сокет устанавливается в активное состояние (прослушивание) при запуске программы. Все подключившиеся клиенты автоматически заносятся как элемент списка (свойство connections). Саму информацию о дате и времени сервер рассылает по таймеру в виде отформатированных текстовых строк:

procedure TServerForm.TimerITimerlSender: TObject);
var i: Integer;
s: string;
ms: TMemoryStatus;
Begin
with ServerSocket.Socket do
for i: =0 to ActiveCcnnections-I do
Connections[i].SendText('T'+TimeToStr(Now));
GlobaiMemoryStatus(ms);
s: =Format('%1OdK', [(ms.dwAvaiiPageFile + ms.dwAvaiiPhys) div 1024]); with ServerSocket.Socket do
for i: =0 to ActiveConnections-I do
Connections [ i ]. SendText ( ' M' +s );
End;

Сервер может отреагировать на сообщение от клиента. Ответ следует отправлять через параметр socket произошедшего события onClientRead:

procedure TServerForm.ServerSocketClientRead (Sender: TObject;
Socket: TCustomWinSocket);
Begin
Memo1.Lines.Add(Socket. ReceiveText );
Socket.SendText( ' I am understand' );
End;

К сокетам проявляют интерес многие разработчики, что можно объяснить их универсальностью и широким распространением. Если вы не нашли чего-то для вас необходимого в компонентах TClientSocket и TServerSocket, или наоборот — сочли их слишком сложными в применении, вы можете использовать компонент TPowersock, разработанный компанией NetMasters. Он находится также на странице Internet Панели инструментов.


Поделиться:



Последнее изменение этой страницы: 2019-10-03; Просмотров: 207; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.067 с.)
Главная | Случайная страница | Обратная связь