Автор работы: Пользователь скрыл имя, 04 Мая 2014 в 11:08, курсовая работа
СУБД SQLite является легковеснойвстраиваемой, это значит, что все операции с данными выполняются внутри приложения без использования сервера базы данных. Исходный код данной СУБД находится в свободном доступе. Доступ к данным в базе происходит через подключения к базе данных, которые мы открываем через вызов соответственной функции DLL.
Для взаимодействия приложения с СУБД SQLite в настоящий момент используются различные интерфейсы, такие как встроенный интерфейс SQLite,JDBC, ODBC и т.п. Однако, нет реализации интерфейса, поддерживающего взаимодействие клиента с сервером СУБД при помощи Pipeпод Windows.
1. Исследование предметной области…….…………………….…………….…5
1.1. Постановка задачи…....…………………….…………….………………..5
1.2. Описание SQLite……….…………...…….…………….………………….7
1.2.1. Устройство и характеристики СУБД SQLite……………...….........7
1.2.2. Методы работы с базой данных……………………….…………....8
1.3. ОписаниеPIPE под Windows…………...…...…………...………………10
1.3.1. Общие понятия ………………………..…………...……………….10
1.3.2. Именованные каналы………………..……………...……………....10
1.3.3. Методы WinAPI для передачи данных…………......……………...12
2. Замысел технического решения….…………………….…………………….15
2.1. Реализация взаимодействия через PIPE…......…………………………..15
2.2. Исполнение запросов кSQLite…………......………………....………….16
3. Описание программы……………….………..…...………………...………...17
3.1. Сервер………………………………...…...……………………………….17
3.2. Клиент…………………………...…………...…………………………….21
3.3. API……………………….....…………………….………………………...22
4. Заключение……….…………………………………….…………………...…24
5. Список используемой литературы…….…………….……………………….
Передача данных в канале может осуществляться синхронно или асинхронно. Когда функции работают синхронно, они передают управление следующему оператору только после завершения. Это означает, что выполнение потока программы может быть заблокировано на неопределенный срок, пока он ожидает завершения выполнения операции. Вероятность такого исхода велика из-за блокировок канала, то есть потоку приходится ждать, пока снимут блокировку с канала, только потом проводить операции.
В случае асинхронного запуска управление к следующему оператору переходит мгновенно после вызова функции, даже если та еще не завершена. Это позволяет проводить длительные операции в фоновом режиме в другом потоке, когда главный поток может работать дальше.
Для осуществления межпроцессного взаимодействия используются такие функции WinAPI как:
HANDLE WINAPI CreateNamedPipe(
_In_ LPCTSTR lpName,
_In_ DWORD dwOpenMode,
_In_ DWORD dwPipeMode,
_In_ DWORD nMaxInstances,
_In_ DWORD nOutBufferSize,
_In_ DWORD nInBufferSize,
_In_ DWORD nDefaultTimeOut,
_In_opt_ LPSECURITY_
);
BOOL WINAPI ConnectNamedPipe(
_In_ HANDLE hNamedPipe,
_Inout_opt_ LPOVERLAPPED lpOverlapped
);
HANDLE WINAPI CreateFile(
LPCTSTR lpFileName,
_In_ DWORD dwDesiredAccess,
_In_ DWORD dwShareMode,
_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
_In_ DWORD dwCreationDisposition,
_In_ DWORD dwFlagsAndAttributes,
_In_opt_ HANDLE hTemplateFile
);
BOOL WINAPI WriteFile(
_In_ HANDLE hFile,
_In_ LPCVOID lpBuffer,
_In_ DWORD nNumberOfBytesToWrite,
_Out_opt_ LPDWORD lpNumberOfBytesWritten,
_Inout_opt_ LPOVERLAPPED lpOverlapped
);
BOOL WINAPI ReadFile(
_In_ HANDLE hFile,
_Out_ LPVOID lpBuffer,
_In_ DWORD nNumberOfBytesToRead,
_Out_opt_ LPDWORD lpNumberOfBytesRead,
_Inout_opt_ LPOVERLAPPED lpOverlapped
);
BOOL WINAPI CloseHandle(
_In_ HANDLE hObject
);
Задача по реализации клиентского API к СУБД с помощью PIPE под Windows сводится к 2 основным этапам:
В проекте реализованы SQL команды, не возвращающие ответ пользователю. То есть такие как Insert, Update, Delete и т.п. После исполнения клиент только получает либо ответ об успешном выполнении, либо информацию об ошибке.
Существует два вида каналов: именованные и анонимные. Анонимные используются для передачи между родительским и дочерним приложением. Так как в данном проекте используются независимые сервер и клиент, анонимные каналы использовать не представляется возможным.
Поэтому для передачи SQL запроса с клиентского приложения на сервер, где находится СУБД SQLite, используется метод взаимодействия при помощи именованных каналов. При запуске сервера создается именованные канал. После по названию канала клиентское приложение связывается с сервером
Так как с сервером взаимодействует несколько клиентских приложений, возникает проблема идентификации каждого клиента в канале. Для этого используется буферы и маркеры для каждого клиентского приложения.
Сервер был реализован таким образом, что для каждого подключенного клиента создается свой потоки вся работа происходит в этом контексте. Таким образом исчезает задача идентификации каждого клиентского приложения так как в каждом потоке существует только одно приложение, для которого хранятся буферы и маркер.
Клиент представляет собой консольное приложение. В нем происходит ввод SQL запроса к серверу, его передача, прием и отображение ответа.
Для взаимодействия клиентского и серверного приложения требуются следующие функции:
Во время запуска сервера происходит подключение к СУБД. При подключении создается дескриптор подключения, за счет которого выполнятся все запросы к базе данных.
Так как сервер многопоточный, дескриптор подключения должен быть доступен всем потокам. Синхронизация доступа и блокировки реализованы в СУБД SQLite, поэтому достаточно отправить запрос на выполнение.
После исполнения запроса проводится проверка на возникшие ошибки. Если произошла ошибка, то информация о ней передается на клиент а СУБД никаких изменений в базу данных не вносит.
В случае успешного выполнения запроса клиенту передается ответ об успешном выполнении, а на сервере управление переходит к вызвавшему потоку.
Структурная схема сервера представлена на «рис.1». Интерфейс сервера представлен на «рис.2».
При запуске сервера создается именованный канал с именем \\.\\pipe\\SamplePipe. Канал открывается для чтения и записи. Режим приема сообщений. Буферы размером в 512 байт.
Рис.1. Структурная схема сервера
После успешного создания канала происходит подключение к базе данных при помощи функции sqlite3_open(). Работа ведется с базой данных my_1_database.dblite. Если ее существует файла, то создается новая пустая база данных. В противном случае открывается уже существующая.
Так как сервер многопоточный, дескриптор подключения для всех потоков один. Таким образом, для всех клиентов существует одно подключение к базе данных.
Если все предыдущие шаги выполнены успешно, сервер переходит в ожидание подключения клиента. После подключения создается поток, в котором происходит обработка подключения. А основной поток переходит в ожидание нового подключения.
Блок-схема работы потока представлена на «рис.3». В созданном потоке происходит чтение входящей строки. Для этого вызывается функция ReadFile(). Если во время чтения не произошло ошибок, то вызывается функция void GetAnswerToRequest( wchar_t* pchRequest, LPTSTR pchReply, LPDWORD pchBytes ). Блок-схема работы функции GetAnswerToRequest представлена на рис.4.
Так как API SQLite работает со строками типа char, а при работе с PIPE строки типа wchar_t. Поэтому перед передачей SQL запроса происходит приведение его типа к char. После передачи полученного запроса и его исполнения клиенту передается либо строка с ошибкой, либо ответ, что запрос исполнен успешно.
Рис.2. Результат работы серверного приложения после запуска
Рис.3. Структурная схема одного потока на сервере
Рис.4. Структурная схема функции GetAnswerToRequest
Результат запуска клиента представлен на «рис.5». Его структурная схема клиента представлена на «рис.6».
Основной задачей клиентского приложения является демонстрация возможностей разработанного API. Для этого создается объект server, конструкотору которого передается имя канала, к которому подключиться.
Рис.5. Результат работы клиентского приложения после запуска
Рис.6. Структурная схема клиентского приложения
Исполняемый запрос пользователь вводит с клавиатуры. После нажатия клавиши Enter Происходит передача запроса на сервер, его исполнение и возврат результата.
После исполнения запроса клиент прекращает свою работу.
Для взаимодействия с сервером реализован класс Pipe_SERVER, исходный код которого находится в файле «SQLite_API.h» и представлен в Приложении. Функции в API:
Для использования функция API создается объект класса Pipe_SERVER, с помощью которого и происходит все взаимодействие.
В конструкторе класса происходит предварительная настройка подключения, то есть инициализация имени канала.
Для подключения к серверу требуется вызвать метод connect(). В этом методе с помощью функции WinAPI CreateFile() происходит инициализация канала на стороне клиента. То есть сохраняется HANDLE, через который происходит запись и прием сообщений.
С помощью метода send_data (wchar_t *chRequest, int length) производится передача строки chRequest длиной length байт. Передача запроса выполняется при помощи вызова функции WriteFile().
Для получения ответа от сервера вызывается метод recieve_data(). С помощью функции ReadFile() происходит чтение из канала в переменную chResponse, являющуюся глобальной в классе. После успешного чтения прочитанное сообщение можно получить, обратившись к chResponse из кода клиента.
С помощью метода cleanup() производится отключение от сервера, вызывая функцию CloseHandle(). После закрытия соединения вся работа с объектом завершается.
Заново можно использовать существующий объект соединения, вызвав функцию connect(). Объект нельзя связать с другим сервером.
В заключение следует сделать вывод, что использование Pipe на ОС Windows упрощает разработку различных клиент-серверных приложений. Засчет того, что в Pipe используются такие же методы WinAPI, как и для работы с файлами, время разработки существенно сокращается.
В ходе выполнения курсового проекта был разработан интерфейс, позволяющий с помощью Pipe в ОС Windows реализовать взаимосвязь клиентского приложения с сервером СУБД.
Данный интерфейс не требует привязки к определенной СУБД так как передается только SQL запрос. А сами алгоритмы работы с СУБД реализованы на стороне сервера. Есть возможность использовать на сервере любой интерфейс для работы с СУБД.
С помощью разработанного API появляется возможность использования БД не на локальном компьютере, а на сервере в локальной сети. Для этого требуется только задать требуемое имя канала.
Так как разработанный API является
прослойкой между клиентом и сервером
и выполняет транспортные функции, то
имеется возможность увеличения функциональности
сервера и клиента без внесения изменений
в API.
5. СПИСОК ИСПОЛЬЗУЕМОЙ ЛИТЕРАТУРЫ
ПРИЛОЖЕНИЕ 1
CppNamedPipeServer.cpp
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <strsafe.h>
#include "iostream"