ГЛАВА 13
Клиент-серверное взаимодействие посредством использования сокетов
Давайте присмотримся — что реально предлагают нам описанные выше средства клиент-серверного обмена данными? Браузеры автоматически формируют графическое отображение Web-страниц, посланных сервером. Для стандартного Web-сайта этого оказывается вполне достаточным, но что делать, когда нужно строить клиент-серверное взаимодействие, основанное на передаче/приеме данных, которые не являются HTML-документами? Или нужно создавать решения, в рамках которых вообще нет места браузерам, и клиентская программа сама должна формировать представление информации?
В таких случаях прибегают к сокетам. Сокеты — это объекты, которые инкапсулируют в себе все необходимые средства для обмена данными в сетях Интернет/интранет. Эти объекты сами создают соединения и посылают/принимают данные, что позволяет программисту избавиться от многих забот и организовать взаимодействие между различными программными компонентами в масштабах сетей так же легко, как, например, чтение и запись в файл. Итак, рассмотрим эти объекты подробнее.
Клиентский сокет
Этот объект предназначен для установления связи с сервером. Точнее, с серверным сокетом, даже если этот сокет выполнен на другом языке программирования. Нахождение нужного сервера осуществляется в сети по его имени, либо IP-адресу. После установления соединения программа может взаимодействовать с сервером, а именно — посылать и принимать данные. Интересно то, что эти данные могут быть произвольного типа. Значки компонентов TServerSocket И TClientSocket, используемые сервером и клиентом в сетевом взаимодействии, показаны
Работать с клиентским сокетом довольно просто. Достаточно указать сервер, его порт, на котором расположена интересуемая служба, а после того, активизировать сокет. После установки соединения вам становятся доступны методы, позволяющие осуществлять прием/передачу данных, которые приведены в табл. 13.1. Таблица 13.1. Некоторые свойства объектов класса TClientSocket
Свойство
Описание
ClientType
Определяет тип клиента с позиций работы с потоками передачи/приема данных. Значение ctNonBlocking позволяет вести с сервером асинхронную работу, посредством операторов чтения/записи. Альтернативный вариант — ctBlocking устанавливает поток обмена данными с сервером, через который и ведется работа
Socket
Определяет объект типа TClientwinSocket, который и представляет программе все сокетные сервисы. Будет описан чуть позже
Active
Определяет — активно ли соединение
Address
Содержит IP-адрес сервера
Host
Содержит имя (DNS) сервера
Port
Определяет порт, на котором установлена служба, с которой требуется соединиться
Service
Определяет название службы, точнее — протокола высокого уровня (HTTP, FTP, POP), по которому будет вестись работа. Если используется собственный формат обмена данными, то поле можно оставлять пустым
Обратите внимание, что при использовании сокетов программисту предоставляются альтернативные пути идентификации сервера. Часто в одноранговых, с точки зрения топологии, локальных сетях применяются протоколы типа NetBEUI — базовый протокол производства Microsoft или IPX/SPX — сети, основанные на технологиях Novell. В этих сетях компьютеры не имеют своих IP-адресов и идентифицируются по имени компьютера. Чтобы работать в таких сетях, нужно вместо поля Address устанавливать значение host.
Если создаваемое приложение будет работать в IP-сетях, то лучше определить параметр Address по следующей причине. Даже если в сети работает служба DNS (см. гл. 1), то все равно сокетные компоненты используют IP-адреса для указания конечного получателя данных. Эти адреса ими извлекаются из запросов к DNS, сопоставляющих имени — IP-адрес. Этот процесс требует определенного времени и сопряжен с возможностью возникновения ошибок. Поэтому лучше сразу указывать IP-адрес машины-сервера. Если приложение будет развернуто в сети Ethernet, не использующей DNS, то просто необходимо указывать IP-адрес.
Перечисленные свойства устанавливают общие характеристики сокета. Основную же нагрузку при клиент-серверном взаимодействии несет на себе объект, указанный в параметре socket. Наиболее часто используемые методы объектов класса iciientsocket указаны в табл. 13.2. Таблица 13.2. Некоторые методы объектов класса Tdientsocket
Метод
Описание
Open
Открывает соединение
Close
Закрывает соединение
Как видим, эти методы не предоставляют прямого интерфейса для отправки или получения данных, они находятся все в том же объекте socket. События объектов класса Tdientsocket описаны в табл. 13.3. Таблица 13.3. События объектов класса Tdientsocket
Событие
Описание
OnConnect
Возникает, когда установлено соединение с сервером
OnConnecting
Условием возникновения этого события является попытка установления соединения с сервером
OnDisconnect
Возникает при отсоединении от сервера
OnError
Как следует из названия, причиной появления этого события является возникновение ошибки
OnLookup
Означает начало процесса сопоставления имени сервера через службу DNS
OnRead
Возникает при приеме сокетом данных, которые нужно передать в программу для обработки
OnWrite
Означает готовность сокета к приему данных, которые будут вслед за тем отправлены серверу i
Как видим, данный объект инкапсулирует только свойства и методы касательные соединения. Для непосредственной работы с данными служит объект класса TCiientwinSocket, доступ к которому может осуществляться посредством Свойства Socket объекта ClientSocket.
Класс TClientwinSocket
Этот класс инкапсулирует в себе свойства и методы, обеспечивающие взаимодействие с сервером. Основные свойства объектов данного класса представлены в табл. 13.4. Таблица 13.4. Некоторые свойства объектов класса TCiientwinSocket
Свойство
Описание
ClientType
Свойство аналогично соответствующему свойству объекта класса TClientSocket
Addr
Содержащая полное описание данного сокета (адрес, имя в DNS, протокол, порт)
Connected
Булевское выражение, отображающее состояние — подключен ли данный сокет к серверу?
LocalAddress
Содержит IP-адрес клиента
LocalHost
Содержит имя компьютера клиента в сети
LocalPort
Указывает номер сетевого порта, который используется данным сокетом
LookupState
Содержит идентификатор состояния сокета в период открытия соединения. Принимает три значения: Isldle, IsLookupAddress и IsLookupService. Первое значение показывает отсутствие какой-либо деятельности. Второе — поиск IP-адреса через доменное имя, используя службу DNS. Последнее — установление типа службы (протокола высокого уровня), с которой будет вестись работа
RemoteAddr
. Структура, аналогичная Addr, но относящаяся к серверу
RemoteAddress
Содержит IP-адрес сервера
RemoteHost
Содержит имя сервера
RemotePort
Указывает номер порта сервера
Как видно из табл. 13.4, свойства объектов класса TCiientwinSocket более детально описывают состояние сокета, что позволяет программе анализировать его и определять свои дальнейшие действия. Методы таких объектов описаны в табл. 13.5. Таблица 13.5. Некоторые методы объектов класса TCiientwinSocket
Метод
Описание
Close
Закрывает текущее соединение
LookupName
Извлекает из URL часть, являющуюся именем ресурса и заполняет соответствующее поле записи, описывающей удаленный или локальный ресурс (TlnAddr)
LookupService
То же, что и LookupName, только касательно названия службы (протокола высокого уровня)
Open
Открывает соединение
ReceiveBuf
Считывает в буфер информацию, пришедшую на сокет с сервера
ReceiveLength
Содержит число бит (символов), которые получены соке-том, и могут быть прочитаны
Отправляет содержимое буфера, указанного в параметре вызова метода серверу
SendStream
Перенаправляет поток, указанный в качестве параметра, серверу
SendStreamThenDrop
Действие аналогично предыдущему с закрытием соединения после завершения передачи
SendText
Отправляет содержимое строки, указанной в качестве параметра, серверу
Данный объект предоставляет все возможности для отправки/приема данных при использовании типа ctNonBiocking сокета. Как видим, здесь есть два сорта операторов чтения и записи, работающие с буферами или строковыми переменными. Кроме того, присутствуют эквивалентные методы для отправки данных. В случае, когда нужно считать данные в поток или отправить содержимое потока серверу, используется тип последнего TWinSocketStream, который создается на основе объекта ClientWinSocket. Методы объектов класса TWinSocketStream представлены в табл. 13.6.
Таблица 13.6. Некоторые методы объектов класса TWinSocketStream
Метод
Описание
Create
Создает поток, ассоциированный с сокетом, указанным в качестве параметра. При получении/отправке данных нужно уже взаимодействовать с этим потоком
Destroy
Уничтожает существующий поток
Read
Считывает данные из потока в буфер
WaitForData
Переходит в режим ожидания готовности сокета к отправке/приему данных
Write
Записывает данные из буфера в поток
Использование потока допустимо в случае, когда клиент принадлежит к типу ctBiocking. При ассоциации потока с объектом clientwinsocket чтение/запись происходит уже не непосредственно из/в сокета, а в созданном потоке, что позволяет работать с ним, как, например, с потоком файлового ввода/вывода.
При создании приложения, которое будет взаимодействовать с сервером посредством сокетов, прежде всего,, нужно внести данные о сервере в свойства объекта clientsocket. После этого, через свойство socket можно получить доступ к соответствующему объекту clientwinsocket. Если используется асинхронная передача информации, т. е. клиент имеет тип ctNonBiocking, то посредством вызова необходимых методов можно принимать/отправлять данные клиенту. В противном случае, с данным сокетом необходимо сопоставить поток, который и будет осуществлять прием/передачу данных. При использовании этого типа клиента события onRead и onWrite, разумеется, не имеют никакого смысла, и поэтому не возникают.
Пример реализации сокетного клиента
Вернемся к примеру, который мы начали реализовывать в предыдущей главе. А именно, речь шла об ActiveX-форме, которая должна отображать данные заказа, предоставлять возможность для распечатки счета и отправлять на сервер реквизиты покупателя, с целью последующего их сохранения в базе данных фирмы. В этом случае, уже неважно, что речь идет об ActiveX-элементах управления. Если бы форма не внедрялась в Web-страницу, то работа с сокетами была бы полностью аналогична.
Для того чтобы добавить эти интерактивные возможности, нужно, как обычно, создавать два компонента программы — на стороне сервера и стороне клиента. Сначала реализуем клиентскую часть.
Поместим в проект компонент clientsocket. После этого нужно установить его параметры. Адрес сервера, установленного на локальную машину, как отмечалось выше 127.0.0.1, имя хоста — localhost или имя компьютера в сети. Наше приложение, работая на стороне клиента, лишь однажды отправит данные через сокет, поэтому наиболее простым вариантом его реализации является применение метода sendText, без использования потоков в программе. Исходя из этого, тип сокета установим в ctNonBiocking. Обычно, Web-сервер имеет номер сетевого порта равный 80. Это значит, что наша серверная программа должна иметь другой сетевой порт, например — 800. Главное, чтобы при назначении номера порта не возникло конфликтов с другими сетевыми службами из-за одинаковых номеров. Таким образом, присвоим свойству Port значение 800.
После инициации соединения с сервером, например, путем установки свойства Active в True, сокет автоматически ищет соответствующий ресурс, и после его нахождения проверяет готовность серверного сокета к приему данных. Как только такое уведомление получено (на низком сетевом уровне), сокет инициирует событие ciientsocketwrite. Как раз в соответствующую данному событию процедуру мы и поместим код, отсылающий содержимое заполненных полей на сервер.
На самом деле, можно по-разному закодировать данные. Все зависит от вкуса и конкретных привычек программиста. Однако существует тенденция к усилению роли стандартного использования данных путем их представления в формате extensible Markup Language (в дальнейшем — XML).
Этот язык представляет собой набор базовых требований к реализациям собственных средств разметки с целью унификации документооборота и обмена данными. Поясню вышесказанное. Предположим, что наша фирма "Два кирпича" имеет пять региональных представительств. Каждое из этих представительств, в свою очередь продает получаемые материалы, через свои Web-сайты. Более того, несколько раз в день головная фирма рассылает представительствам информацию об ассортименте и ценах на товары в виде прайс-листов. Разумеется, все изменения должны автоматически вноситься в базу данных фирмы и содержимое сайта. Ручное внесение изменений недопустимо в связи с необходимостью постоянного контроля над целостностью данных, что при большом количестве позиций крайне затруднительно. Следует искать автоматизированные решения. Для обеспечения простого взаимодействия с информационными системами конкретных представительств необходимо иметь стандарт представления данных. В нашем случае, с одной стороны, информационная система должна анализировать содержимое документа с целью выявления нужных данных, которые будут внесены в БД фирм, а с другой стороны, документ, составленный по этим правилам, должен иметь более широкие возможности для визуального представления данных, нежели простая таблица.
Понятно, что возможности HTML достаточно скудно реализуют выдвинутые требования, поскольку отражают лишь форматирование данных. Невозможно прямо указать тип передаваемых данных, назначить им какие-либо специальные атрибуты. Использование форматирования, базирующегося на языке XML, позволяет передавать не только сами данные, но и указывать их принадлежность. Рассмотрение этого языка выходит за рамки данной книги, но в примере мы используем следующие соглашения касательно формата представления передаваемых данных.
Все данные будут посылаться через сокетное соединение в обычном текстовом формате.
Для идентификации передаваемых сведений будем использовать теговые конструкции, наподобие элементов языка HTML. Все теги должны закрываться.
Примем к использованию следующие элементы:
элемент Имя клиента. Ему соответствует тег <CUSTNAME>;
элемент Адрес клиента. Тег — <CUSTADDRESS>;
элемент Банковские Сведения. Тег — <CUSTBANK>.
На основании этого представления нам (в смысле программирования серверной части) будет легко разобраться, какие сведения к чему относятся.
Реализуем процедуру шифрования данных и последующей их отправки (листинг 13.1). Объект клиентский сокет назовем cisock. Листинг 13.1. Реализация процедуры шифрования и отправки данных через сокетное соединение примера
procedure Tshop.ClSockWrite(Sender: TObject; Socket: TCustomWinSocket);
begin Content:='<CUSTNAME>'+custname.text+ '</CUSTNAMEXCUSTADDRESS>'+ custaddress.Text+'</CUSTADDRESSXCUSTBANK>' +custbank.Text+'</CUSTBANK>'; Cisock.Socket.SendText(content);
end;
Чтобы использовать шаблон для введения кода процедуры, вызываемой как отклик на событие, нужно сделать двойной щелчок мышью в названии процедуры в окне Object Inspector напротив соответствующего события. В данном случае, это событие OnWrite.
Как видим, процесс обмена данными через сокеты предельно прост, несмотря на то, что его реализация на низком уровне представляет собой очень содержательную задачу. Вот как проявляются фантастические возможности RAD-среды Delphi!
Теперь осталось только вписать одну строчку в процедуру Tshop.printbtnciick, а именно
clsock.active:=true
Как только пользователь нажмет на кнопку Печать, сокет произведет попытку соединения с сервером. В случае если соединение случится, то пойдет выполнение процедуры cisockwrite. В противном случае, возникнет исключительная ситуация. При разработке реальных проектов нужно всегда помещать вызов метода Open в конструкцию, обеспечивающую корректную работу с исключительными ситуациями try ... except.
Серверный сокет
Серверный сокет предполагает обмен данными с клиентами. В принципе, от клиентской реализации он отличается тем, что способен работать с несколькими клиентами одновременно. На базе серверного сокета можно создавать программы — серверы, которые предоставляют возможность внедрять собственные протоколы верхнего уровня, т. е. реализовывать различные схемы обмена данными. Свойства объектов класса TServerSocket представлены в табл. 13.7. Таблица 13.7. Основные свойства объектов класса TServerSocket
Свойство
Описание
Socket
Представляет собой ссылку на объект типа TServerWinSocket, который и предоставляет основные сервисы
Server Type
Определяет тип сервера с позиций работы с потоками передачи/приема данных. Значение stNonBlocking позволяет вести асинхронную работу с сервером посредством операторов чтения/записи. Альтернативный вариант— значение stThreacffllocking устанавливает поток обмена данными с сервером, через который и ведется работа
ThreadCacheSize
Содержит число потоков, которые кэшируются в памяти. Для ускорения работы с клиентами, объект ServerSocket после завершения соединения с клиентом не выгружает из памяти содержимое потоков ввода/вывода с целью последующего их использования при работе с другими клиентами. Данный параметр устанавливает число хранимых в памяти потоков
Active
Определяет — активен ли сокет
Port
Содержит номер сетевого порта, на который установлена служба, работу которой обеспечивает данный сокет
Service
Содержит название службы, точнее — протокола высокого уровня (HTTP, FTP, POP), по которому будет вестись работа. Если используется собственный формат обмена данными, поле можно оставлять пустым
Аналогично клиентскому сокету, в сетевом сокете основную функциональную нагрузку несет на себе объект, указанный в поле socket, который будет описан чуть позже. Наиболее часто используемые методы объектов класса
TServerSocket описаны табл. 13.8. Таблица 13.8. Некоторые методы объектов класса TServerSocket
Метод
Описание
Open
Включает сокет
Close
Отключает сокет
Аналогично клиентскому сокету, вызов метода open устанавливает значения поля Active в true, а вызов close — в false. События, которые могут возникать у объектов класса TServerSocket, приведены в табл. 13.9. Таблица 13.9. События объектов класса TServerSocket
Событие
Описание
OnClientConnect
Возникает после завершения процесса соединения с клиентом
OnCl lent Disconnect
Возникает после рассоединения с клиентом
OnClientError
Возникает при наличии ошибки
OnClientRead
Идентифицирует состояние, когда необходимо извлекать присланные от клиента данные .
OnClientWrite
Идентифицирует состояние, когда клиентский сокет ждет передачи данных от серверного
OnGetSocket
Возникает, когда установлено соединение с клиентом, и этому соединению можно назначить свой экземпляр объекта, реализующий основные возможности работы с клиентом — ServerClientWinSocket. Если программист хочет реализовать специфичные задачи, то он должен написать процедуру, возвращающую конкретный объект класса TServerClientWinSocket, который станет обслуживать запросы конкретного клиента (в результате соединения с которым и возникло это событие)
OnGetThread
Возникает, когда можно назначать конкретный поток сетевому соединению
OnThreadEnd
Возникает, когда соединение с клиентом завершено и соответствующий ему поток уничтожается
OnThreadStart
Возникает в связи с инициализацией потока, ассоциированного с данным сетевым соединением
OnAccept
Возникает, как только подтверждено создание соединения с клиентом
OnListen
Возникает непосредственно перед началом процесса последовательных опросов порта на предмет новых клиентских соединений
Как и в случае с клиентским сокетом, для работы с сокетными подключениями создается объект, доступный посредством свойства Socket. Необходимо учитывать, что серверный сокет может обслуживать несколько подключений одновременно, и поэтому для каждого подключения существует свой экземпляр объекта, предоставляющий сетевые сервисы. Графически последовательность выбора свойств объектов для доступа к непосредственному
Обратите внимание, что, как и в случае клиентского сокета, объект ServerSocket служит для установления и обслуживания общих свойств соединения, но в нем свойство socket указывает не на конечное соединение, а на другой объект — serverwinsocket, который в свою очередь осуществляет менеджмент соединений. Свойства последнего сведены в табл. 13.10. Таблица 13.10. Некоторые свойства объекта serverNinSocket
Свойство
Описание
ActiveConnections
Содержит число текущих соединений
ActiveThreads
Содержит число запущенных потоков, посредством которых и происходит обмен данными
Connections
Возвращает число текущих соединений с клиентами
IdleThreads
Содержит число потоков, хранящихся в кэше сокета
ServerType
Определяет тип сервера с позиций работы с потоками передачи/приема данных. Значение stNonBlocking позволяет вести с сервером асинхронную работу посредством операторов чтения/записи. Альтернативный вариант— stBlocking устанавливает поток обмена данными с сервером, через который и ведется работа
ThreadCacheSize
Содержит число потоков, которые кэшируются в памяти
Addr
Содержит полное описание данного сокета (адрес, имя в DNS, протокол, порт)
Connected
Массив объектов класса TCustomWinSocket, предоставляющий доступ к методам и свойствам этих объектов. Каждому соединению соответствует свой индекс массива, в порядке подключения
Handle
Содержит Handle окна в графической системе Windows, на которое должны приходить сообщения о состоянии сокета. По умолчанию, все сообщения приходят на окно, содержащее сам сокет
LocalAddress
Содержит IP-адрес сервера
LocalHost
Содержит имя сервера в DNS
LocalPort
Указывает номер порта, на котором размещена эта сетевая служба
RemoteAddr
Содержит IP-адрес клиента
RemoteHost
Содержит имя клиента в DNS
ReraotePort
Указывает номер сетевого порта, используемого программой, с которой ведется взаимодействие
SocketHandle
Содержит Handle, присвоенное данному сокету
Handle окна, или другого объекта, это целое число, которое им присваивается операционной системой Windows. При обычном создании окон с помощью Delphi программисту незачем использовать этот параметр, но если окна создаются путем прямого вызова API-функций или модернизируются ими, к примеру, делаются полупрозрачными или овальными, то параметр Handle используется повсеместно. Кроме того, если вы хотите работать напрямую с системой Windows, окнами и процессами другого приложения, то индексация нужных объектов также осуществляется путем использования этих параметров. Методы объекта serverwinSocket сведены в табл. 13.11. Таблица 13.11. Некоторые методы объекта ServerwinSocket
Метод
Описание
Disconnect
Закрывает то сокетное соединение, Handle которого указан в параметре
Listen
Инициирует процесс опроса порта на предмет получения запроса на сетевое соединение
Close LookupName
Закрывает текущее соединение
Извлекает из URL часть, являющуюся именем ресурса, и заполняет соответствующее поле записи, описывающей удаленный или локальный ресурс (ilnAddr)
LookupService
То же, что и предыдущий, только касательно названия службы (протокола высокого уровня)
Open
Открывает соединение
ReceiveBuf
Считывает информацию, пришедшую на сокет с сервера в буфер
ReceiveLength
Содержит число бит (символов), которые получены сокетом, и их нужно считать
ReceiveText
Возвращает строку, содержащую данные, полученные в результате взаимодействия с клиентом
SendBuf
Отправляет содержимое буфера, указанного в параметре, серверу
SendStream
Перенаправляет поток, указанный в качестве параметра, серверу
SendStreamThenDrop
Действие аналогично предыдущему с закрытием соединения после завершения передачи
SendText
Отправляет содержимое строки, указанной в качестве параметра, серверу
Легко заметить, что основные методы, предназначенные для приема/отправки данных, одинаковы у объектов класса TServerwinSocket и TClientwinSocket. Связано это с тем, что они оба являются наследниками класса TCustonwinSocket. Естественно, что и работа с данными методами объектов указанных классов одинакова. Поэтому, чтобы узнать, как читать и отправлять данные, используя серверный сокет, загляните в соответствующий раздел описания клиентского сокета.
События объектов класса TServerwinSocket и TServerSocket практически одинаковы, поэтому на них мы подробно останавливаться не будем.
Пример реализации сонетного сервера
Как обычно, вернемся к нашему примеру, который мы реализуем на протяжении изложения всего материала книги. В результате выполнения предыдущих примеров у нас получился клиентский модуль, который отправляет на сервер информацию о клиенте с целью последующего ее сохранения в БД фирмы.
Мы можем создать сокетный сервер, используя обычные визуальные средства Delphi. Это освободит нас от обработки множества событий. По сути, серверные приложения, базирующиеся на сокетах, создаются точно так же, как и клиентские. Отличие заключается в том, что после установки всех свойств и активизации объекта клиентский сокет пытается установить соединение с сервером, а серверный опрашивает сетевой порт. Как бы там ни было, все, что нужно сделать в примере, — это поместить объект в форму, установить его свойства и активизировать. Только нужно поместить обработчик события OnClientRead.
Давайте создадим новый проект под названием appserv. В форму следует поместить кнопку Button, компонент servetsocket, свойству name которого придадим значение SrvrSock, port — 800, host — localhost. При нажатии на кнопку этот объект должен активизироваться. Присвоим надписи на кнопке (поле caption) значение Старт! Для активизации серверного модуля в процедуре Buttoniciick (шаблон которой вызывается, как обычно, путем двойного щелчка мышью по этой кнопке в режиме проектирования) следует вписать строчку.
SrvrSock.active:=true;
Поскольку наш проект должен добавлять полученные данные в БД в форме SQL-команды, то на форму следует добавить объект Query. Присвоим ему это же имя. База данных, по-прежнему, должна называться shop.
Осталось реализовать процедуру чтения данных от клиента и записи их в базу данных, которая приведена в листинге 13.2. Листинг 13.2. Реализация обработчика события OnClientRead
procedure TForml. SrvrSockClientRead(Sender: TObject," Socket: TCustomWinSocket); type Custinfo = record name: string; address: string;
bank: string;
end;
function ExtractXMLcontent(s, constr: string): string; begin Result:=Copy(s,(Pos('<'+constr+'>',s)+Length(constr}+2),
(Pos('</'+constr+'>',s)-(Pos(I<'+constr+I>',s) +Length(constr)+2)));
end; var content: string;
currcust: custinfo; numcust:integer;
begin
content:=Socket.ReceiveText;
currcust.name:=ExtractXMLcontent(content,'CUSTNAME');
currcust.address:=ExtractXMLcontent(content,'CUSTADDRESS');
currcust.bank:=ExtractXMLcontent(content,'CUSTBANK');
Query.close;
Query.sql.Clear;
Query.sql.Add('SELECT ID FROM klients');
query.open;
query.Last;
numcust:=strtoint(query.FieldValues['ID'] ) +1;
Query.close;
Query.SQL.Clear;
Query.sql.Add('INSERT INTO klients(ID, KlientsName, KlientsAddress, KlientsBank) Values ('+inttostr(numcust) + ',"'+currcust. name+'", "'+currcust.address+'", "r+currcust.bank+'"}');
Query.ExecSQL;
end;
Эта процедура содержит функцию ExtractXMLcontent, возвращающую значение данных, занесенных в теги, передаваемые в функцию с переменной constr.
Как видно, основная часть процедуры представляет собой код работы с базой данных, поэтому на нем мы не будем останавливаться, т. к. используются стандартные команды языка SQL, описанные в гл. 3.
Если нам потребовалось бы одновременно обслуживать несколько подключений, то строка
content:=Socket.ReceiveText;
перешла бы в
content:=Socket.connections[i].ReceiveText;
где i — номер соединения, с которым ведется работа.
Таким образом, при нажатии на кнопку Старт! серверный сокет переходит в режим опроса сетевого порта. Как только клиентский сокет установил соединение и прислал данные, инициируется обработчик события onCiientRead, после чего полученные данные извлекаются, декодируются и сохраняются в базе данных.