русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

Работа с базами данных


Дата добавления: 2015-06-12; просмотров: 3113; Нарушение авторских прав


База данных (БД) – это поименованная совокупность взаимосвязанных данных, находящихся под управлением системы управления базами данных (СУБД). Различают иерархические, сетевые и реляционные СУБД. В C++ Builder используется несколько механизмов и инструментов для работы с базами данных: BDE (Borland Database Engine), ADO (ActiveX Data Object) позволяет соединяться с базами данных, используя объекты ActiveX.

5.1. Основные концепции реляционных баз данных

Реляционная база данных (РБД) представляет собой одну или совокупность взаимосвязанных таблиц, состоящих из записей. С позиции реляционной алгебры БД – это совокупность отношений над n множествами M1, M2, ..., Mn. Например, это множества студентов, преподавателей, экзаменов. Отношение представляет собой таблицу. При этом наборы вида <m1, m2, ..., mn>, где mk – элемент из Mk, называются кортежами (строками таблицы или записями). Запись состоит из атрибутов, являющихся столбцами таблицы (полями записи). Каждый столбец имеет уникальное имя, которое записывается в верхней части таблицы и является именем поля. Атрибут, который может быть использован для однозначной идентификации конкретной записи, называется первичным ключом. Для таблицы Student (табл. 9) первичным ключом может быть номер студенческого билета. Для ускорения доступа к данным по первичному ключу в СУБД имеется механизм, называемый индексированием. Индекс представляет собой древовидный список, указывающий на местоположение записи для каждого первичного ключа. Возможно индексирование отношения с использованием атрибутов, отличных от первичного ключа (вторичного ключа), например фамилии студента.

Таблица 9 (Student)

Stud_Id StudName Kurs Address Predmet Prepod
Котов П.А. Витебск, Ленина, 1 Prog Романчик
Павлов А.И. Минск, Репина, 2 Matan Примачук
Коваль Н.К. Гомель, Пушкина, 3 Difur Громак

 



Для поддержания ссылочной целостности данных в нескольких взаимосвязанных таблицах используется механизм внешних ключей. При этом некоему атрибуту одного отношения назначается ссылка на первичный ключ другого отношения, тем самым закрепляются связи подчиненности между этими отношениями. При этом отношение, на первичный ключ которого ссылается внешний ключ другого отношения, называется master-отношением, а отношение, от которого исходит ссылка, называется detail-отношением, или подчиненным отношением. После назначения такой ссылки СУБД имеет возможность автоматически отслеживать вопросы «ненарушения» связей между отношениями. Если делается попытка вставить в подчиненную таблицу запись, для внешнего ключа которой не существует соответствия в главной таблице, СУБД генерирует ошибку. Если попытаться удалить из главной таблицы запись, на первичный ключ которой имеется ссылка из подчиненной таблицы, или изменить первичный ключ, СУБД также генерирует ошибку. Существуют два подхода к удалению и изменению записей из главной таблицы:

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

2. Распространить всякие изменения в первичном ключе главной таблицы на подчиненную таблицу.

5.2. Проектирование баз данных

Проектирование базы данных можно представить в виде следующей последовательности шагов:

1. Разработка модели БД, которая включает: идентификацию функциональной деятельности предметной области; идентификацию объектов, которые осуществляют эту деятельность; идентификацию взаимосвязей между объектами.

2. Определение атрибутов, которые уникальным образом идентифицируют каждый объект (первичный ключ). Первичный ключ гарантирует, что в таблице не будет содержаться двух одинаковых строк.

3. Устанавливание связи между объектами и проведение операции исключения избыточности данных – нормализация таблиц.

Таким образом, для проектируемой базы данных сначала определяются таблицы, поля, индексы и связи между таблицами

Существует несколько типов связей между таблицами: «один-к-одному», «один-ко-многим», «многие-ко-многим». Связь «один-к-одному» представляет собой простейший вид связи данных, когда первичный ключ таблицы является внешним ключом, ссылающимся на первичный ключ другой таблицы. Связь «один-ко-многим» отражает реальную взаимосвязь в предметной области. Эта связь описывает механизм классификаторов или кодов. Например, 01.01 – математика. Связь «многие-ко-многим» в явном виде в РБД не поддерживается.

Процесс нормализации. После разработки структуры таблиц проектируемую базу данных следует проанализировать, используя правила нормализации. Нормализация заключается в приведении таблиц к нормальным формам. Этот процесс включает: устранение повторяющихся групп (приведение к первой нормальной форме), удаление частично зависимых атрибутов (приведение ко второй нормальной форме), удаление транзитивно зависимых атрибутов (приведение к третьей нормальной форме).

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

Приведение к первой нормальной форме. Если поле в данной записи содержит более одного значения, такие группы данных называются повторяющимися. Первая нормальная форма не допускает наличия таких многозначных полей. Рассмотрим пример БД, содержащей таблицу Student (табл. 10; номер студенческого билета является первичным ключом). Для приведения таблицы к первой нормальной форме мы должны поле Address разбить на два поля, содержащие город и улицу, если в дальнейшем будет выполняться обработка данных по регионам.

Приведение ко второй нормальной форме. Следующий шаг в процессе нормализации состоит в удалении всех неключевых атрибутов, которые зависят только от части первичного ключа. Такие атрибуты называются частично зависимыми. Для приведения таблицы ко второй нормальной форме удалим из нее атрибуты Predmet и Prepod и создадим две таблицы (табл. 11 и 12), которые будут содержать только эти атрибуты, и они же будут составлять их первичный ключ.

 

Таблица 10 (Student)

Stud_Id StudName Kurs City Street
Котов П.А. Витебск Ленина, 1
Павлов А.И. Минск Репина, 2
Коваль Н.К. Гомель Пушкина, 3

 

 

Таблица 11 (Subject)

Subj_Id Subj_Name Hour
Prog
Matan
Difur

 

Таблица 12 (Prepod)

Prepod_Id Prepod_Name
Романчик
Примачук
Громак

 

Кроме этого, будем использовать также таблицу Exams (табл. 13).

Таблица 13 (Exams)

Exam _Id Stud_Id Subj_Id Exammark ExamDate
6/01/06
10/01/06
20/01/06

 

Приведение к третьей нормальной форме. Третий этап процесса приведения таблиц к нормальной форме состоит в удалении всех неключевых атрибутов, которые зависят от других неключевых атрибутов или вычисляются по ним. Каждый неключевой атрибут должен быть логически связан с атрибутом, являющимся первичным ключом. Например, из таблицы можно удалить атрибут Stipend. Получим табл. 14.

Таблица 14 (Stipend)

Stud_Name Summa
Котов П.А.
Павлов А.И.
Коваль Н.К.

 

Добавим таблицу, связывающую преподавателей и предметы (табл. 15).

Таблица 15 (Sub_Prepod)

Prepod_Id Subj_Id

 

Разбиение информации на мелкие единицы способствует повышению надежности базы данных, но снижает ее производительность.

На последнем шаге разработки БД необходимо спланировать вопросы безопасности и конфиденциальности информации и определить права на использование и на модификацию данных.

Теперь можно приступать к созданию приложений, работающих с базами данных. Рассмотрим сначала средства для разработки таблиц.

5.3. Утилита Database Desktop

Database Desktop – это старая утилита, которая поставляется для создания таблиц и интерактивной работы с таблицами различных форматов. При этом могут использоваться таблицы для локальных БД типа Paradox, dBase, MSAccess а также распределенных и SQL-серверных баз данных InterBase, Oracle, Informix, Sybase.

После запуска Database Desktop выберите команду меню File|New|Table для создания новой таблицы. Появится диалоговое окно выбора типа таблицы, например Paradox, DB2, dBase, MSAccess, MSSQL. После выбора типа таблицы появляется диалоговое окно, в котором можно определить поля таблицы и их тип. Таблицы создаются в online-режиме в рабочем пространстве DataBase Desktop, связанном с каталогом, который необходимо предварительно установить.

Для таблиц типа Paradox можно определить поля, находящиеся в начале записи и составляющие первичный ключ. Достаточно дважды щелкнуть мышью по этому полю. С таблицей можно связать некоторые свойства.

Validity Checks (проверка правильности) – относится к полю записи и определяет минимальное и максимальное значение поля, а также значение по умолчанию.

Table Lookup (таблица для «подсматривания») – позволяет вводить значение в таблицу, используя уже существующее значение в другой таблице.

Secondary Indexes (вторичные индексы) – обеспечивают доступ к данным в порядке, отличном от задаваемого первичным ключом. Вторичные ключи могут использоваться в подчиненной таблице для указания ссылки на главную таблицу.

Referential Integrity (ссылочная целостность) – позволяет задать связи между таблицами и поддерживать эти связи на уровне ядра.

Password Security (парольная защита) – позволяет защитиь таблицу паролем.

Table Language – позволяет задать языковый драйвер.

В табл. 16 приведены типы полей записей для БД типа Paradox.

 

Таблица 16

Alpha Строка длиной от 1 до 255 байт
Number Числовое поле длиной 8 байт для чисел от 10-308 до 10308 с 15 значащими цифрами
Money Форматированное числовое поле для отображения денежного знака
Short Числовое поле длиной 2 байта для целых чисел от -32768 до 32767
Long Integer Числовое поле длиной 4 байта для целых чисел от -2147483648 до 2147483648
BCD Числовое поле данных в формате BCD (Binary Coded Decimal). Может иметь от 0 до 32 цифр после десятичной точки
Date Поле даты длиной 4 байта
Time Время в миллисекундах от полуночи
Timestamp Обобщенное поле даты длиной 8 байт. Содержит дату и время
Memo Поле для хранения символов, суммарное число которых превышает 255
Graphic Поле для графической информации
OLE Содержит OLE-данные: образы, звук, видео
Logical Содержит значения T(true) или F(false)
Autoincrement) Содержит значение типа integer, которое автоматически увеличивается на 1, начиная с 1
Binary Cодержит любую двоичную информацию
Bytes Строка длиной от 1 до 255 байт

Поля таблиц формата dBase описаны в табл. 17.

 

Таблица 17

Character Строка
Float (numeric) Числовое поле размером от 1 до 20 байт
Number (BCD) Числовое поле размером от 1 до 20 байт, содержащее данные в формате BCD
Date Поле даты длиной 8 байт
Logical Поле может содержать только значения «истина» – T, t, Y, y или «ложь» – F, f, N, n
Memo Поле для хранения последовательности символов, длина которой превышает 255 байт
OLE Поле, содержащее OLE-данные
Binary Поле, содержащее двоичную информацию

 

 

В таблицах dBase не существует первичных ключей. Однако это обстоятельство можно преодолеть путем определения уникальных (Unique) и поддерживаемых (Maintained) индексов (Indexes).

Отметим, что использование утилиты Database Desktop является одним из способов создания таблиц. Например, таблицы можно создавать средствами конкретной СУБД.

5.4. Структурированный Язык Запросов SQL

Язык Запросов SQL – основной язык для работы с реляционными базами данных. Состав языка SQL следующий:

Язык манипулирования данными. Состоит из команд: SELECT (выбрать), INSERT (вставить), UPDATE (обновить), DELETE (удалить).

Язык определения данных. Используется для создания и изменения структуры БД и ее составных частей – таблиц, индексов, представлений (виртуальных таблиц). Основными его командами являются: CREATE DATABASE (создать базу данных), CREATE TABLE(создать таблицу), CREATE INDEX(создать индекс), CREATE PROCEDURE (создать сохраненную процедуру), ALTER DATABASE (модифицировать базу данных), ALTER TABLE(модифицировать таблицу), ALTER INDEX(модифицировать индекс), ALTER PROCEDURE (модифицировать сохраненную процедуру), DROP DATABASE (удалить базу данных), DROP TABLE(удалить таблицу), DROP INDEX(удалить индекс), DROP PROCEDURE(удалить сохраненную процедуру).

Язык управления данными (управления доступом). Состоит из двух основных команд: GRANT (дать права), REVOKE (забрать права).

5.5. Команды языка манипулирования данными

Наиболее важной командой языка манипулирования данными является команда SELECT. Формат команды SELECT в языке SQL:

SELECT поля FROM таблицы WHERE условие;

Базовыми операциями являются: выборка, проекция, соединение, объединение.

Операция выборки позволяет получить все либо часть строк таблицы:

SELECT * FROM Student; – получить все строки таблицы Student

SELECT * FROM Student WHERE Kurs=2 – получить подмножество строк таблицы, удовлетворяющих условию Kurs=2. Точка с запятой является стандартным признаком конца команды, который вставляется автоматически.

Операция проекции позволяет выделить подмножество столбцов таблицы:

SELECT StudName FROM Student WHERE Kurs=2; – получить имена студентов второго курса.

Операция соединения позволяет соединять строки из более чем одной таблицы:

SELECT StudName, Exammark FROM Students, Exams WHERE Students.Stud_Id =Exams.Stud_Id – получить список студентов и экзаменационных оценок.

Операция объединения позволяет объединять результаты отдельных запросов. Предложение UNION объединяет вывод двух или более SQL-запросов:

SELECT name FROM employee WHERE country = "Беларусь" UNION SELECT contact_nаме, FROM customer WHERE country = "Беларусь"; – получить список работников и заказчиков, проживающих в Беларуси.

Простейшие конструкции команды SELECT. Список выбираемых элементов может содержать: имена полей, символ ‘*’, вычисления, литералы, функции, агрегирующие конструкции.

Вычисления:

SELECT StudName, Summa, Summa * 1.15 FROM Stipend – получить список студентов и их стипендию, увеличенную на 15%.

Литералы. Для наглядности результата в запросах можно использовать литералы – строковые константы, заключенные в одинарные или двойные кавычки. Например:

SELECT StudName, "получает", Summa, " в месяц" FROM Stipend

Два или более столбца, имеющих строковый тип, можно соединять друг с другом, а также с литералами с помощью операции конкатенации (||). Например:

SELECT "сотрудник " || first_name || " " || last_name FROM Prepods

Работа с датами. В языке SQL имеются возможности конвертирования дат в строки и работы с датами. Внутренне дата содержит значения даты и времени. Внешне дата может быть представлена строками различных форматов, например:

· “October 27, 2005”

· “10/27/2005”

Дата может неявно конвертироваться в строку (из строки), если имеет один из допустимых форматов. Например:

SELECT StudName, ExamDate FROM Student, Exams WHERE ExamDate > '6/01/06' – получить список студентов, сдававших экзамен после 6/06/06.

Значения дат можно сравнивать, а также вычитать одну дату из другой.

Агрегатные функции. К агрегатным функциям относятся функции вычисления суммы (SUM), максимального (MAX) и минимального (MIN) значений столбцов, среднего арифметического (AVG), количества строк, удовлетворяющих заданному условию. Например: SELECT count(*),sum(budget),avg (budget), min(budget), max(budget) FROM department WHERE head_dept = 100 – вычислить количество отделов, являющихся подразделениями отдела 100, их суммарный, средний, минимальный и максимальный бюджеты.

Условия отбора. Директива WHERE содержит условия отбора (предикат). Запрос возвращает только строки, для которых предикат имеет значение true. Типы предикатов, используемых в предложении WHERE:

Сравнение: = (равно); <> (не равно); != (не равно); > (больше); < (меньше); >= (больше или равно); <= (меньше или равно); BETWEEN, IN, LIKE, CONTAINING, IS NULL, EXIST, ANY, ALL.

Предикат BETWEEN задает диапазон значений, для которого истинно значение выражения. Например:

SELECT StudName, Stipend FROM Student WHERE Stipend BETWEEN 120 AND 200 – получить список студентов, стипендия которых больше 120 и меньше 200.

Тот же запрос с использованием операторов сравнения будет выглядеть следующим образом:

SELECT StudName, Stipend FROM Student WHERE Stipend>=120000 AND Stipend<=200000

Предикат IN (NOT IN) проверяет, входит ли заданное значение, предшествующее ключевому слову IN, в указанный в скобках список. Например:

SELECT name FROM employee WHERE job_code IN ("VP", "Admin", "Finan") – получить список сотрудников, занимающих должности «вице-президент», «администратор», «финансовый директор».

Предикат LIKE проверяет, соответствует ли данное символьное значение строке с указанной маской. В качестве маски используются все разрешенные символы (с учетом верхнего и нижнего регистров), а также специальные символы: % – замещает любое количество символов, _ – замещает только один символ. Например:

SELECT StudName FROM Student WHERE StudName LIKE "Ф%" – получить список студентов, фамилии которых начинаются с буквы ‘Ф’.

Предикат CONTAINING аналогичен предикату LIKE, однако он не чувствителен к регистру букв.

Предикат IS NULL принимает значение true только тогда, когда выражение слева от IS NULL имеет значение null (пусто, не определено).

Логические операторы. К логическим операторам относятся NOT, AND, OR.В одном предикате логические операторы выполняются в указанном порядке.

Преобразование типов. В SQL имеется возможность преобразовать значение к другому типу для выполнения операций сравнения. Для этого используется функция CAST.

Изменение порядка выводимых строк. Порядок выводимых строк может быть изменен с помощью предложения ORDER BY в конце SQL-запроса. Это предложение имеет вид: ORDER BY [ASC | DESC]

Способом по умолчанию является упорядочивание «по возрастанию» (ASC). Если указано DESC, упорядочивание производится «по убыванию». Например:

SELECT StudName, Stipend FROM Student ORDER BY StudName – получить список в алфавитном порядке.

Операция соединения. Используется в языке SQL для вывода связанной информации, хранящейся в нескольких таблицах. Операции подразделяются на внутренние и внешние. Связывание производится, как правило, по первичному ключу одной таблицы и внешнему ключу другой таблицы. Предложение WHERE может содержать множественные условия соединений.

Внутренние соединения. Внутреннее соединение возвращает только те строки, для которых условие соединения принимает значение true. Рассмотрим пример запроса:

SELECT StudName, ExamMark FROM Student, Exams WHERE Kurs=2 AND ExamMark=5 – получить список студентов 2-го курса, сдавших экзамен на 5.

В запросе можно использовать способ непосредственного указания таблиц или указания таблиц с помощью алиасов (псевдонимов).

Внешние соединения. Внутреннее соединение возвращает только строки, для которых условие соединения принимает значение true. Внешнее соединение возвращает все строки из одной таблицы и те строки из другой таблицы, для которых условие соединения принимает значение true. Существуют два вида внешнего соединения: в левом соединении (LEFT JOIN) запрос возвращает все строки из таблицы, стоящей слева от LEFT JOIN и только те из правой таблицы, которые удовлетворяют условию соединения. Для правого соединения – все наоборот. Например:

SELECT name, department FROM employee e LEFT JOIN department d ON e.dept_no = d.dept_no – получить список сотрудников и название их отделов, включая сотрудников, еще не назначенных ни в какой отдел.

5.6. Выполнение инструкций SQL

Для выполнения инструкции SQL создается содержащая ее строка и передается свойству SQL компонента TQuery. Компонент TQuery должен быть помещен на форму, его свойство DatabaseName настроено на нужный алиас (если базы данных не существует, можно создать ее в SQL Explorer).

Для создания статического запроса можно ввести SQL-предложение в свойство SQL компонента TQuery.

Способ построения динамического запроса состоит в создании строки и добавлении ее в свойство SQL при выполнении приложения. Для выполнения запроса, изменяющего структуру данных, вставляющего или обновляющего данные на сервере, нужно вызвать метод ExecSQL() компонента TQuery. Например:

Query1->Close();

Query1->SQL->Clear();

Query1->SQL->Add("Delete * from Country where Name = 'Blr' ");

Query1->ExecSQL();

Приведем упрощенный синтаксис SQL-предложения для создания таблицы на SQL-сервере:

CREATE TABLE table (<col_def> [, <col_def> | <tconstraint> ...]);

где table – имя создаваемой таблицы; <col_def> – описание поля; <tconstraint> – описание ограничений и/или ключей (квадратные скобки [] означают необязательность, вертикальная черта | означает «или»).

Приведем несколько примеров создания таблиц с помощью SQL.

Пример. Простая таблица с конструкцией PRIMARY KEY на уровне поля:

CREATE TABLE REGION ( REGION REGION_NAME NOT NULL PRIMARY KEY, POPULATION INTEGER NOT NULL);

Предполагается, что в базе данных определен домен REGION_NAME, например, следующим образом:

CREATE DOMAIN REGION_NAME AS VARCHAR(40) CHARACTER SET WIN1251 COLLATE PXW_CYRL;

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

 

Queryl->Close ();

Queryl->SQL->Clear ();//Очистить свойство SQL от запроса

Queryl->SQL->Add(str) ; //Присвоить текст свойству SQL

Query1->Open(); // выполнить команду SQL

5.7. Разработка приложений баз данных

Механизм BDE. Механизм BDE (Borland Database Engine), обеспечивающий работу визуальных компонентов БД, действует как интерфейс между приложением и базой данных. BDE обращается к драйверам для баз данных указанного типа, возвращая запрошенные данные. Используя BDE, можно получить доступ к локальным стандартным базам данных, к источникам данных ODBC и к SQL-серверам баз данных. Чтобы получить доступ к содержимому БД, приложению необходимо знать только ее алиас.

Использование визуальных компонентов. C++Builder предоставляет разработчикам следующие компоненты для работы с базами данных из VCL:

1. Компоненты управления данными на вкладке Data Control (такие как TDBEdit, сетка TDBGrid или DBNavigator) для отображения и редактирования записей на форме.

2. Компоненты доступа к данным на вкладке Data Access. Компонент источника TDataSource служит как интерфейс межкомпонентной связи между таблицей TTable или запросом Tquery и компонентом управления.

C++Builder поддерживает трехступенчатую модель разработки приложения баз данных. В этой модели компонент управления связан с компонентом источника TDataSource, а тот, в свою очередь, получает фактические данные из таблицы или запроса посредством механизма BDE.

Рассмотрим работу компонента доступа.

Невидимый компонент TDataSource действует как интерфейс между некоторым объектом набора данных (таблица, запрос) и визуальным компонентом управления. С одной стороны, все наборы данных должны быть ассоциированы с некоторым источником. С другой стороны, каждый компонент управления должен быть ассоциирован с источником, чтобы получать данные для отображения и редактирования.

Свойство DataSet компонента TDataSource определяет имя конкретного набора данных (таблицы или запроса), который питает данный источник. С помощью этого свойства можно переключаться с одного набора данных на другой во время выполнения программы. Следующий код реализует попеременное подключение объекта источника DataSource1 к таблице заказчиков "Заказчики" или к таблице "Заказы":

 

if (DataSourcel->DataSet == "Заказчики")

DataSourcel->DataSet = "Заказы";

Чтобы синхронизировать работу компонентов управления на двух формах, достаточно установить свойство DataSet на один и тот же набор данных:

void__fastcall TForm2::FormCreate (TObject *Sender) {

DataSource1->DataSet = Form1->Table1;}

С компонентом TDataSource связаны три события. Событие OnDataChange возникает при перемещении курсора на новую запись. Событие OnStateChange возникает при изменении свойства State наборов данных. Например, следующий обработчик события будет отслеживать изменения состояния таблицы MyTable.

void__fastcall TForm1::StateChange(TObject *Sender)

{String s;;

switch (MyTable->State) {

case dsInactive: s="Таблица неактивна"; break;

case dsBrowse: s = "Идет просмотр"; break;

case dsEdit: s = "Идет редактирование"; break;

case dsInsert: s = "Идет вставка записи"; break;

}

// Вывод текстовой строки s

Form1->Caption=s;

}

Событие OnUpdateData возникает перед фактическим обновлением текущей записи.

3. Компоненты DDE.

Таблицы. Компонент TTable устанавливает прямую связь с таблицей БД посредством BDE, причем все записи или столбцы этой таблицы становятся доступными для приложения.

Компонент TTable имеет следующие свойства:

Active – разрешает или запрещает режим просмотра «живых данных» таблицы на этапе проектирования. Значение true или метод Open() открывают просмотр таблицы. Значение false или метод Close() закрывают просмотр;

DatabaseName – содержит псевдоним базы данных или путь к ее каталогу. Использование псевдонима всегда предпочтительнее: вы можете переназначить физический носитель данных. Перекомпиляция приложения не требуется – просто измените путь на вкладке Aliases в утилите конфигурации BDE;

TableName – позволяет выбрать фактическое имя таблицы из выпадающего списка;

Exclusive – разрешает или запрещает другому приложению обращаться к таблице, пока вы ее используете сами;

IndexFiles – открывает диалог выбора индексного файла для таблицы;

IndexName – задает правило сортировки данных, отличное от упорядочивания по первичному ключу (primary key order);

Filter – позволяет устанавливать критерий фильтрации, в соответствии с которым адресуется некоторое подмножество записей таблицы;

MasterFields и MasterSource – участвуют в образовании связи двух таблиц (ведущей и ведомой) по принципу master-detail.

С компонентом TTable связаны следующие методы:

GotoCurrent() – синхронизирует перемещения курсора по нескольким табличным компонентам, ассоциированным с одной и той же фактической таблицей;

First(), Next(), Prior(), Last() и MoveBy() – используются для навигации по данным таблицы;

SetKey(), FindKey(), FindNearest(), GotoKey() и GotoNearest() – используются для поиска по специфическим значениям ключей;

Append(), Insert(), AppendRecord() и InsertRecord() – добавляют новую запись к таблице;

Delete() – вычеркивает текущую запись;

Edit() – разрешает приложению модифицировать записи, a Post() – вызывает фактическое изменение содержимого БД.

Запросы. Компонент TQuery обеспечивает доступ к нескольким таблицам одновременно. Вид возвращаемого набора данных зависит от SQL-запроса, который может быть либо статическим, когда параметры запроса задаются на стадии проектирования, либо динамическим, когда параметры определяются во время выполнения программы.

Компонент TQuery имеет следующие свойства:

Active – разрешает или запрещает режим просмотра «живых данных», возвращаемых запросом на этапе проектирования;

DatabaseName – содержит псевдоним базы данных или полный путь к ее каталогу, необходимые для разрешения запроса;

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

Аналогично таблице компонент запроса TQuery также инкапсулирует следующие методы:

First(), Next(), Prior(), Last() и MoveBy() – используются для навигации по результатам динамического запроса;

Append(), Insert(), AppendRecord() и InsertRecord() – добавляют новую запись к таблице;

Delete() – удаляет текущую запись;

Edit() – разрешает приложению модифицировать записи;

Post() – вызывает фактическое изменение содержимого БД.

Следующая процедура иллюстрирует процесс создания простой формы для базы данных StudentBase:

1. Поместите на форму Form1 пять наборов TTable, TDataSource, TDBGrid, TDBNavigator.

2. Установите свойства объектов таблиц Table1 – Table5:

DatabaseName =StudentBase; Table1Name =students,

Table2Name=predmets, Table3Name =prepods, Table4Name=exams,

TableName5=raspisanie.

3. Установите свойства объектов источников DataSourcel ->

DataSet=Table1, …, DataSource5 -> DataSet=Table5

4. Установите свойства компонентов отображения данных

DBGrid1 -> DataSource= DataSource1, …, DBGrid5 ->DataSource= DataSource5

5. Установите свойство Active=true для таблиц, чтобы сразу же отобразить данные в сетках на форме.

6. Создайте новую форму Form2 и поместите на нее компоненты Query1, Table1, DataSourse1, DBGrid1. Задайте свойства этих компонентов.

7. В свойстве SQL компонента Query1 задайте SQL-запрос:

SELECT StudentsName, ExamMark, PrepodName, PredmetName

FROM students, exams, predmets,prepods,raspisanie

WHERE students.Id_stud=exams.Id_stud

AND raspisanie.Id_predmet=exams.Id_predmet

AND raspisanie.Id_prepod=prepods.Id_prepod

AND exams.Id_predmet=predmets.Id_predmet

AND predmets.PredmetName LIKE 'Програм'

AND exams.ExamMark >'5';

8. Выполните компиляцию и запустите приложение. На рис. 19 показан результат выполнения приложения.

Чтобы связать ведущую таблицу students с ведомой таблицей exams необходимо выполнить следующие олерации:

1. Активизируйте ведомую таблицу Table5 и установите свойство MasterSource = DataSource1.

 

 

 

Рис. 19. Результат выполнения приложения

 

2. Дважды щелкните мышью в графе значений свойства MasterFields и в открывшемся окне редактора связи полей выберите Id_stud (связующее поле таблиц) из выпадающего списка Available Indexes; задайте Id_stud в списках Detail Fields и Master Fields; нажмите кнопку Add, чтобы добавить в список Joined Fields соединение Id_Stud-> Id_Stud; нажмите кнопку OK, подтверждая сделанный выбор.

Следующая процедура иллюстрирует процесс создания формы со статическим запросом к таблице EMPLOYEE для получения всей информации о служащих, зарплата которых превышает заданную величину.

1. Поместите компонент TQuery на форму.

2. Установите псевдоним адресуемой базы данных сервера в свойстве DatabaseName. В примере используется псевдоним BCDEMOS локальной демонстрационный базы данных, содержащей, в частности, таблицу служащих некоторого предприятия.

3. Откройте строчный редактор списка, введите команду SQL:

SELECT * FROM EMPLOYEE WHERE Salary>40000 и нажмите кнопку ОК.

4. Поместите на форму компонент TDataSource и установите его свойство DataSet = Query1.

5. Поместите на форму компонент управления TDBGrid и установите его свойство DataSource = DataSource1.

6. Установите свойство Active = true для запроса Query1 с тем, чтобы сразу же отобразить живые данные в компоненте управления.

Далее приводится пример приложения для выполнения динамических SQL-запросов к таблице служащих.

Свойство SQL компонента TQuery имеет тип TStrings и содержит список текстовых строк наподобие массива. Листинг показывает обработчик события Button1Click, реализующий ввод запроса пользователем при нажатии кнопки на форме. Введенная команда SQL записывается в строчный массив (того же типа TStrings) свойства Memo1->Lines компонента TMemo. Результаты запроса можно, как и в предыдущем примере, отобразить с помощью компонента TDBGrid.

void__fastcall TForm1::Button1Click(TObject *Sender) {

// Проверить, введена ли какая-то строка в Memo1

if (strcmp(Memo1->Lines->Strings[0].c_str(), "") = = 0) (

MessageBox(0, "Не введен SQL-запрос", "Ошибка", MB_OK) ;

return;

}

else {

// Исключить предыдущий запрос, если он имел место

Queryl->Close ();

// Очистить свойство SQL от предыдущего запроса

Queryl->SQL->Clear ();

// Присвоить введенный в Memo1 текст свойству SQL

Queryl->SQL->Add(Memo1->Lines->Strings[0].c_str()) ;

try{

Query1->Open(); // выполнить команду SQL

}

catch(EDBEngineError* dbError){} .// обработка ошибок BDE

{

for (int i=0; i<dbError->ErrorCount; i++)

MessageBox (0, dbError[i].Message.c_str(), "SQL Error", MB_OK) ;

}

}

}

Для динамического формирования текста командной строки SQL во время выполнения программы удобно использовать стандартную функцию языка С sprintf(). Эта функция замещает параметры форматирования (%s, %d, %n и т. д.) передаваемыми значениями. Например, в результате подстановки значений параметров форматирования

tblName = "Student";

fldName = "Kurs";

fldValue = 2;

char sqls[80];

sprintf(sqls, "SELECT * FROM %s WHERE %s = %d", tblName, fldName, fldValue);

символьный массив sqls будет содержать следующую команду:

SELECT * FROM Student WHERE Kurs=2.

Далее созданный запрос выполняется

Query1->Close() ;

Query1->SQL->Clear() ;

Query1->SOL->Add(sqls);

try{

Query1 -> Open(); // выполнить команду SELECT

}

catch(EDBEngineError* dbError) // обработка ошибок BDE

{ }

}

Метод Open() предназначен для передачи серверу команды Select языка SQL для исполнения. Существуют другие команды SQL, например команда UPDATE, которая обновляет содержимое некоторой записи, но не возвращает какой бы то ни было результат. Для исполнения сервером таких запросов следует использовать метод ExecSQL() вместо метода Open().

5.8. Соединения с базой данных и транзакции

Компонент TDatabase позволяет создавать локальный псевдоним БД, не требуя его наличия в конфигурационном файле BDE, и имеет следующие свойства:

AliasName – содержит псевдоним существующей базы данных, определенный утилитой конфигурации BDE. Указание этого свойства является альтернативой значения свойства DriverName;

DatabaseName – позволяет создать локальный псевдоним базы данных в дополнение к значениям AliasName или DriverName;

DriverName – содержит имя драйвера BDE при создании локального псевдонима по значению DatabaseName. Указание этого свойства является альтернативой значения свойства AliasName;

Params – содержит строчный массив параметров одиночного соединения (полный путь, имя сервера и т. д.).

Компонент TDatabase может использоваться для управления транзакциями. Примером транзакции является перевод денежных средств с банковских счетов. Такая транзакция состоит в добавлении суммы к новому счету и вычитании этой суммы из исходящего счета. Если выполнение любой из операций терпит неудачу, вся операция считается незавершенной. SQL-серверы дают возможность «прокручивать назад» команды при возникновении ошибки, не производя изменений в базе данных. Как правило, транзакция содержит несколько команд, поэтому начало транзакции надо отметить методом StartTransaction(). Как только транзакция началась, все ее исполняемые команды находятся во временном состоянии до тех пор, пока один из методов Commit() или Rollback() не отметит конец транзакции. Вызов Commit() фактически модифицирует данные, а вызов Rollback() отменяет всякие изменения.

Ниже приводится листинг, который реализует транзакцию по изменению адреса фирмы на примере связанных таблиц CUSTOMER и ORDERS. Старый адрес, введенный пользователем в область редактирования EditOld, заменяется на новый, введенный в область редактирования EditNew. В этом примере компонентный объект Database1 используется для одиночного, поддерживающего выполнение одиночной транзакции, соединения с базой данных. Этот объект необходимо каким-то образом связать с псевдонимом базы данных: или установкой соответствующих свойств компонента, или определив параметры соединения (такие как тип драйвера, имя сервера, имя пользователя, пароль) во время выполнения программы. Воспользуемся первым способом соединения на стадии проектирования формы приложения, установив нужные значения свойств компонента:

void__fastcall TForm1::Button1Click(TObject *Sender) {

char sqls[250]; // массив для хранения команды SQL

try{

Database1->StartTransaction ();

Query1->SQL->Clear () ;

// Изменить EditOld на EditNew в таблице CUSTOMER

sprintf(sqls, "UPDATE CUSTOMER SET Addrl = \"%s\" WHERE

(Addrl = \"%s\")", EditNew->Text.c_str(), EditOld->Text.c_str());

Query1->SQL->Add(sqls) ;

Query1->ExecSQL ();

Query1->SQL->Clear () ;

// Изменить EditOld на EditNew в таблице ORDERS

sprintf(sqls, "UPDATE ORDERS SET ShipToAddrl = \"%s\" WHERE

(ShipToAddrl = \"%s\")", EditNew->Text.c_str(),

EditOld->Text.c_str()) ;

Query1->SQL->Add(sqls) ;

Query1->ExecSQL();

// Внести все изменения, сделанные до этого момента

Database1->Commit();

Table1->Refresh();

Table2->Refresh();

}

catch(EDBEngineError* dbError) // обработка ошибок BDE

{

for (int i=0; i<dbError->ErrorCount; i++)

MessageBox (0, dbError[i].Message.c_str(), "SQL Error", MB_OK);

Database1->Rollback() ;

return;

} catch (Exception* exception) // обработка других исключений

{}

}

5.9. Управление данными

Остановимся на особенностях использования компонента навигатора TDBNavigator. Нажимая на кнопки компонента First, Prior, Next и Last, можно перемещаться от записи к записи, а с помощью кнопок Insert, Delete, Edit, Post, Cancel и Refresh – производить редактирование.

Компонент TDBNavigator имеет следующие свойства:

DataSource – соединяет кнопки управления панели навигатора с компонентами доступа к наборам данных через компонент источника. Изменяя значение этого свойства во время выполнения программы, можно использовать один и тот же компонент для навигации по разным таблицам. Например, можно разместить на форме два компонента редактируемого ввода DBEdit1 и DBEdit2, связанные с таблицами CustomersTable и OrdersTable через источники данных CustomersSource и OrdersSource, соответственно. Когда пользователь выбирает название фирмы (поле Company в DBEdit1), навигатор тоже должен соединяться с источником CustomersSource, а когда активизируется номер заказа (поле OrderNo в DBEdit2), навигатор должен переключаться на источник OrdersSource. Чтобы реализовать подобную схему работы навигатора, необходимо написать обработчик события OnEnter для одного из объектов компонента редактирования, а затем присвоить этот обработчик другому объекту;

VisibleButtons – позволяет убрать ненужные кнопки, например кнопки редактирования на форме, предназначенной для просмотра данных. Во время выполнения программы можно динамически прятать или вновь показывать кнопки навигатора – в ответ на определенные действия пользователя или на изменения состояния приложения. Предположим, был предусмотрен единый навигатор для редактирования таблицы CustomersTable и для просмотра таблицы OrdersTable. Когда навигатор подключается ко второй таблице, желательно спрятать кнопки редактирования Insert, Delete, Edit, Post, Cancel и Refresh, а при подключении к первой таблице – снова показать их;

ShowHint – разрешает или запрещает высвечивать подсказку с названием кнопки навигатора, когда на нее наведен курсор. Значение false (устанавливается по умолчанию) запрещает подсказки для всех кнопок;

Hints – содержит массив текстовых подсказок для каждой кнопки навигатора.

Проектирование формы приложения СУБД в среде C++Builder в простейшем случае требует выполнения следующих действий.

1. Перенесите на форму компонент TTable или TQuery со страницы Data Access и установите его свойства.

2. Перенесите на форму компонент DataSource и в свойстве DataSet укажите ссылку на объект набора данных (например, Table1 или Query1).

3. Перенесите на форму нужные компоненты отображения и редактирования данных со страницы DataControls и в их свойстве DataSource задайте источник данных (например, DataSource1). Определите отображаемое поле набора данных в свойстве DataField.

4. Если на предыдущем шаге вы выбрали компонент TDBGrid, то используйте его совместно с компонентом навигатора TDBNavigator.

Вопросы

1. Что представляет собой псевдоним БД и как он создается?

2. Как создать таблицу с помощью программы Database Desktop?

Какие другие средства для создания таблиц можно использовать?

3. Какие компоненты используются для связи таблиц БД с компонентами визуализации и управления данными DBGrid, DBEdit?

4. Как связать компоненты Table и Query с нужной таблицей БД?

5. Как связать компонент DBNavigator с нужной таблицей БД?

6. Что такое первичные и вторичные индексы для таблицы и как их создать?

7. Что такое SQL и из каких частей он состоит?

8. Что означают следующие SQL-запросы:

a) SELECT name, projectname FROM emploee, project

WHERE empno=team_leader;

б) SELECT name, salary FROM emploee, prohibit

WHERE salary>2900;

9. Как использовать SQL-запрос в C++Builder ?

Упражнения

В следующих упражнениях создать указанные таблицы и записать SQL запрос для выборки данных из обеих таблиц.

1. Построить головную таблицу «Телефонный справочник» с полями: Номер телефона, Адрес, а также вспомогательную таблицу «Население города» с полями: Номер телефона, Фамилия И.О., Год рождения, Пол, Адрес.

2. Головная таблица содержит данные о подразделениях предприятия: Отдел – номер, название (например, Цех1, Бухгалтерия), тип отдела (например, Управление, Производство и т. д.). Вспомогательная таблица содержит сведения о сотрудниках: ID, Фамилия И.О., Год рождения, Пол, Номер_Отдела. Связать таблицы по полю Номер_Отдела.

3. БД содержит следующие связанные таблицы: «Сведения о покупателях»:ID, Фамилия И.О., адрес, Номер банковского счета, номер заказа и «Сведения о заказах»: Наименование товара, ID, Количество, Стоимость, Дата заказа.

4. БД содержит следующие связанные таблицы: «Студенты»: Номер зачётной книжки, Фамилия, Имя, Отчество, Специализация, Курс, Группа; «Учебный план»: Специализация, Курс, Предмет1, Предмет2,…; «Журнал успеваемости»: Фамилия, Имя, Отчество, Предмет 1, Предмет 2, …

5. БД «Абитуриенты» содержит следующие связанные таблицы:
«Сведения об абитуриентах»: Номер личной карточки, Фамилия, Имя, Отчество, Факультет, Специальность; «Сведения о сдаваемых предметах»: Специальность, Предмет; «Сведения об оценках»: Фамилия, Имя, Отчество, Номер личной карточки, Предмет, Оценка.

6. БД «Автомобили» содержит следующие таблицы:
«Общие сведения об автомобиле»: ID, Марка, Тип, Производитель; «Характеристика автомобиля»: Марка, Мощность двигателя, Тип двигателя, Стоимость.

7. БД «Лабораторные занятия» содержит следующие таблицы:
«Преподаватели»: ID, Фамилия, Имя, Отчество, Предмет, Курс, Группа; «Студенты»: ID, Фамилия, Имя, Отчество, Курс, Группа;
«Пропуски занятий»: Фамилия, Имя, Отчество, Курс, Группа, Предмет, Пропущено.

8. БД «Конференция» содержит следующие таблицы:
«Расписание заседаний»: Номер, Название секции, Дата, Время;
«Сведения об участниках»: Фамилия И.О., Название секции, Название доклада; «Оргработа»: Фамилия, Имя, Отчество, Дата приезда, Дата отъезда, Потребность в гостинице, Оргвзнос.

9. БД «Библиотека» содержит следующие таблицы:
«Общая характеристика единицы хранения»: Инвентарный номер, Тип издания (журнал, книга, рукопись), Название; «Характеристика издания»: Тип издания, Авторы, Название, Издательство, Год издания, Номер, Количество страниц.

10. БД «Магазин» содержит следующие таблицы: «Товары»: Артикул, Наименование товара, Количество, Дата поставки, Цена; «Поставщики»: Название организации, Наименование товара, Количество, Дата поставки, Адрес организации; «Покупатели»: Название организации, Наименование товара, Количество, Дата покупки, Адрес покупателя.

11. БД «Поликлиника» содержит следующие таблицы: «Врачи»: Участок, Фамилия И.О., Специальность; «Пациенты»: ID, Фамилия И. О., Диагноз, Возраст, Участок.

12. БД «Спортивная база» содержит следующие таблицы:
«Тренеры»:ID, Фамилия, Имя, Отчество, Вид спорта, Секция;
«Спортсмены»: ID, Фамилия, Имя, Отчество, Вид спорта, Секция, Рейтинг, Возраст.

6. СЕТЕВЫЕ ПРОГРАММЫ И СОКЕТЫ

Понятие «сокет» (socket) означает «гнездо», «разъем» по аналогии с гнездами на аппаратуре. В соответствии с этой аналогией можно связать два «гнезда» соединением и передавать между ними данные. Каждое гнездо принадлежит определенному хосту (host – хозяин, держатель). Каждый хост имеет уникальный IP (Internet Packet) адрес, представляющий группу из четырех чисел, разделенных точками.

Переданная по IP адресу на хост информация поступает на один из портов хоста. Порт определяется числом от 0 до 65535. После того как сокет установлен, он имеет вполне определенный адрес, записывающийся так: [host]:[port]. Например,адрес 127.0.0.1:8888 означает, что сокет занимает порт 8888 на хосте 127.0.0.1 (на данном компьютере). Чтобы не использовать труднозапоминаемый IP адрес, для доступа к хостам сущеествует система имен DNS (DNS – Domain Name Service), поддерживаемая специальным сервером. Цель этой системы – сопоставлять IP адресам символьные имена. Например, адресу 127.0.0.1 в большинстве компьютеров соответствует имя localhost, что означает сам компьютер, на котором выполняется программа.

Сокеты – это абстракция, представляющая узлы соединения двух приложений – клиента и сервера. Клиенты и серверы подключаются к этим узлам через соединение, которое можно представить как гипотетический кабель. Соединения с приложением-сервером всегда устанавливают приложения-клиенты. В обязанность приложения-сервера входит прослушивание клиентов и ожидание соединения. После этого клиенты посылают серверу или получают от него сообщения в виде последовательности символов, а в конце работы закрывают соединение.

Для организации сетевых соединений (сокетов) в C++ Builder используются классы TСlientSocket и TServerSocket из группы компонентов Internet. Ниже описывается работа с компонентом TСlientSocket по установке соединения.

Определение свойств Host и Port.Поместим компонентTClientSocket на форму. Чтобы установить соединение, нужно присвоить свойствам Host и Port компонента TClientSocket значения, соответствующие адресу сервера. Host – это символьное имя компьютера-сервера, с которым надо соединиться (например: localhost, nitro.borland.com или mmf410-2), либо его IP адрес (например: 127.0.0.1, 192.168.0.88). Port – номер порта (от 1 до 65535) на данном хосте для установления соединения. Обычно номера портов выбираются, начиная с 1001 (номера меньше 1000 могут быть заняты системными службами, например, по умолчанию POP – 110, Http – 80).

Открытие сокета. После назначения свойствам Host и Port соответствующих значений можно приступить к открытию сокета. Для этого нужно присвоить свойству Active значения true. Здесь полезно вставить обработчик исключительной ситуации на случай, если соединиться не удается. Открытие сокета можно выполнить также с помощью метода ClientSocket->Open();

Авторизация. На этом этапе вы посылаете серверу свой логин (имя пользователя) и пароль. Этот пункт можно пропустить, если сервер не требует ввода логинов или паролей.

Посылка/прием данных – это, собственно, и есть то, для чего открывалось сокетное соединение;

Закрытие сокета – после выполнения операций необходимо закрыть сокет, присвоив свойству Active значение false или вызовом метода ClientSocket->Close().

Свойства и методы компонента TClientSocket. На рис. 20 и 21 показаны свойства и события компонента TClientSocket в инспекторе объектов. В табл. 18 приведены их краткие описания.

 

 
 

Рис. 20. Свойства компонента TClientSocket

 
 

 

Рис. 21. События компонента TClientSocket

Пример программы-клиента на основе сокета. Поместим на форму компонент TClientSocket, две кнопки Button1 и Button2, два окна типа TEdit и два компонента Memo1 и Memo2. При нажатии на кнопку GetFromServeSendToClient вызывается обработчик события OnClick – Button1Click(). Перед этим в Edit1 нужно ввести хост-имя, а в Edit2 – порт удаленного компьютера. Когда TClientSocket должен прочитать информацию из сокетного соединения, возникает событие OnRead и вызывается функция ClientSocketRead().

 

Таблица 18

Свойства События
Active – True – сокет открыт, а False – закрыт Host – строка (типа String), указывающая на имя компьютера, к которому следует подключиться Address – строка (типа String), указывающая на IP адрес компьютера, к которому следует подключиться. Если вы укажете в Host символьное имя компьютера, то IP адрес будет запрошен у DNS Port – номер порта (от 1 до 65535), к которому следует подключиться Service – строка, определяющая службу (ftp, http, pop и т. д.), к порту которой произойдет подключение ClientType – тип соединения ctNonBlocking или ctBlocking OnConnect – возникает при установлении соединения. В обработчике события можно начинать авторизацию или прием/передачу данных OnConnecting – возникает при установлении соединения, когда соединение еще не установлено. Обычно такие промежуточные события используются для обновления статуса OnDisconnect – возникает при закрытии сокета из вашей программы либо из-за сбоя OnError – возникает при ошибке в работе сокета. Операторы открытия сокета следует заключить в блок try..catch OnLookup – возникает при попытке получения от DNS IPадреса хоста OnRead – возникает, когда удаленный компьютер послал данные OnWrite – возникает, когда вам разрешена запись данных в сокет

 
 

На рис. 22 показана форма приложения в процессе проектирования.

 

 

Рис. 22. Форма приложения-клиента

 

Ниже приводятся коды приложения-клиента.

TForm1 *Form1;

//---------------------------------------------------------------------------

__fastcall TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

{

}

//открытие клиента и установка соединения

void __fastcall TForm1::Button1Click(TObject *Sender)

{

TClientSocket *cs = Form1->ClientSocket; // формируем указатель cs->Close(); // закрытие соединения(если слушали порт ранее)

try

{

cs->Port=Form1->PortEdit->Text.ToInt();// получение номера порта

cs->Host = HostEdit->Text; // получение адреса хоста

cs->Active = true; // установка соединения

}

catch(...)

{

Memo1->Text = "Some problem with connection";// если введены

// неверные значения

}

}

//очистка окна

void __fastcall TForm1::ClearClick(TObject *Sender)

{

Memo1->Clear();

}

// считывание клиентом сообщения

void __fastcall TForm1::ClientSocketRead(TObject *Sender, TcustomWinSocket

*Socket)

{

Memo1->Text = Socket->ReceiveText(); // запись сообщения в поле клиента

}

void __fastcall TForm1::ClientSocketWrite(TObject *Sender,

TCustomWinSocket *Socket)

{

Socket->SendText(Memo2->Text); //

}

// вызов события посылки сообщения

void __fastcall TForm1::Button2Click(TObject *Sender)

{

Form1->ClientSocketWrite(Form1,Form1->ClientSocket->Socket);

}

Ниже описываются методы свойства Socket компонента TClientSocket (свойство Socket, в свою очередь, является объектом класса TсustomWinSocket):

SendText(String) – посылка текстовой строки через сокет;

SendStream() – посылка содержимого указанного потока через сокет. Пересылаемый поток должен быть открыт;

SendBuf(Buf, Count) – посылка буфера через сокет. Буфером может являться любой тип, например структура или простой тип int. Буфер указывается параметром Buf, вторым параметром необходимо указать размер пересылаемых данных в байтах (Count);

ReceiveText() – получить сообщение.

Программирование серверов на основе сокетов. Следует заметить, что для сосуществования отдельных приложений клиента и сервера не обязательно иметь несколько компьютеров. Достаточно иметь лишь один, на котором можно одновременно запустить и сервер, и клиент. При этом в качестве имени компьютера, к которому надо подключиться, нужно использовать хост-имя localhost или IP адрес – 127.0.0.1.

Сервер, основанный на сокетном протоколе, позволяет обслуживать сразу множество клиентов. Причем, ограничение на их количество можно указать самим (или убрать это ограничение, как сделано по умолчанию). Для каждого подключенного клиента сервер открывает отдельный сокет, по которому можно обмениваться данными с клиентом. Другим решением является создание для каждого подключения отдельного процесса (Thread).

Создание сервера включает следующие шаги:

Определение свойств Port и ServerType – чтобы к серверу могли подключаться клиенты, порт, используемый сервером, должен совпадать с портом, используемым клиентом. Свойство ServerType определяет тип подключения.

Открытие сокета – открытие сокета и указанного порта. Осуществляется установкой свойства ServerSocket->Active=true. Автоматически начинается ожидание подсоединения клиентов.

Подключение клиента и обмен данными с ним – клиент устанавливает соединение и начинается обмен данными с ним.

Отключение клиента – клиент отключается и закрывается его сокетное соединение с сервером.

Закрытие сервера и сокета – по команде администратора сервер завершает свою работу, закрывая все открытые сокетные каналы и прекращая ожидание подключений клиентов.

Далее приводится краткое описание компонента TServerSocket. На рис. 23 и 24 приводятся свойства и события компонента, которые отображаются в окне Инспектора объектов. Табл. 19 содержит описание указанных свойств и событий.

Свойство Socket компонента TServerSocket. Как сервер может отсылать данные клиенту или принимать данные? Если вы работаете через события OnClientRead и OnClientWrite, то общаться с клиентом можно через свойство Socket (TCustomWinSocket). Отправка/посылка данных через свойство Socket класса TServerSocket аналогична работе клиента (методы SendText(), SendBuf(), SendStream(), ReceiveText()). Однако следует выделить некоторые полезные свойства и методы, характерные для для сервера:

ActiveConnections (Integer) – количество подключенных клиентов;

ActiveThreads (Integer) – количество работающих процессов;

Connections (array) – массив, состоящий из отдельных классов TClientWinSocket для каждого подключенного клиента. Например, такая команда

ServerSocket1->Socket->Connections[i]->SendText(“Hello!”);

 

 

 
 

Рис 23. Свойства компонента TServerSocket

 

 

 
 

Рис. 24. События компонента TServerSocket

 

 

отсылает i-му подключенному клиенту сообщение “Hello!”);

IdleThreads (Integer) – количество свободных процессов (такие процессы кэшируются сервером, см. свойство ThreadCacheSize);

LocalAddress, LocalHost, LocalPort – соответственно локальный IP-адрес, хост-имя, порт;

RemoteAddress, RemoteHost, RemotePort – соответственно удаленный IP адрес, хост-имя, порт;

методы Lock и UnLock – соответственно блокировка и разблокировка сокета.

 

Таблица 19

Свойства События
Socket – класс TServerWinSocket, через который имеется доступ к открытым сокетным каналам ServerType – тип сервера ThreadCacheSize – количество клиентских процессов (Thread), которые будут кэшироваться сервером. Кэширование происходит для того, чтобы не создавать каждый раз отдельный процесс и не уничтожать закрытый сокет, а оставить их для дальнейшего использования. Тип: int Active –значение True указывает на то, что сервер работает и готов к приему клиентов, а False – сервер выключен Port – номер порта для установления соединений. Порт у сервера и у клиентов должны быть одинаковыми. Рекомендуются значения от 1025 до 65535 Service – строка, определяющая службу (ftp, http, pop и т. д.), порт которой будет использован. Тип:String OnClientConnect – возникает, когда клиент установил сокетное соединение и ждет ответа сервера OnClientDisconnect – возникает, когда клиент отсоединился OnClientError – возникает, когда операция завершилась неудачно OnClientRead – возникает, когда клиент передал серверу данные OnClientWrite – возникает, когда сервер может отправлять данные клиенту по сокету OnGetSocket – в обработчике этого события можно отредактировать параметр ClientSocket OnGetThread – в обработчике события можно определить уникальный процесс (Thread) для каждого клиента канала, присвоив параметру SocketThread нужную подзадачу TServerClientThread OnThreadStart, OnThreadEnd – возникает, когда процесс Thread запускается или останавливается OnAccept – возникает, когда сервер принимает клиента или отказывает ему в соединении OnListen – возникает, когда сервер переходит в режим ожидания подсоединения клиентов

 

Пример. Создадим приложение-сервер. Для этого на форму нужно поместить кнопки Button1 и Button2, поле Edit1 и компоненты Memo1 и Memo2. При создании формы вызывается обработчик события OnCreate (FormCreate), в котором активизируется сервер. Свойство компонента TServerSocket->Active устанавливается в true, что означает, что сокетное соединение открыто и доступно для коммуникации с клиентами. В компоненте Edit1 указано значение прослушиваемого порта. Когда ServerSocket1 должен записать информацию в ClientSocket1, возникает событие OnClientWrite и вызывается функция ServerSocketClientWrite(). На рис. 25 приведена форма приложения в процессе проектирования.

 

 

Рис. 25. Форма приложения-сервера

 

Ниже приводится листинг приложения-сервера.

void __fastcall TForm1::FormCreate(TObject *Sender)

{



<== предыдущая лекция | следующая лекция ==>
Компоненты | Создание собственных компонентов


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 0.823 сек.