API взаимодействия клиентских приложений с сервером СУБД

  • Вид работы:
    Курсовая работа (т)
  • Предмет:
    Информационное обеспечение, программирование
  • Язык:
    Русский
    ,
    Формат файла:
    MS Word
    358,42 Кб
  • Опубликовано:
    2014-04-30
Вы можете узнать стоимость помощи в написании студенческой работы.
Помощь в написании работы, которую точно примут!

API взаимодействия клиентских приложений с сервером СУБД

СОДЕРЖАНИЕ

Исследование предметной области

Постановка задачи

Описание SQLite

Устройство и характеристики СУБД SQLite

Методы работы с базой данных

Описание PIPE под Windows

Общие понятия

Именованные каналы

Методы WinAPI для передачи данных

Замысел технического решения

Реализация взаимодействия через PIPE

Исполнение запросов к SQLite

Описание программы

Сервер

Клиент

Заключение

Список используемой литературы

Приложение 1. CppNamedPipeServer.cpp

Приложение 2 . CppNamedPipeClient.cpp

Приложение 3. SQLite_API.h


Исследование предметной области

Постановка задачи

СУБД SQLite является легковесной встраиваемой, это значит, что все операции с данными выполняются внутри приложения без использования сервера базы данных. Исходный код данной СУБД находится в свободном доступе. Доступ к данным в базе происходит через подключения к базе данных, которые мы открываем через вызов соответственной функции DLL.

Для взаимодействия приложения с СУБД SQLite в настоящий момент используются различные интерфейсы, такие как встроенный интерфейс SQLite, JDBC, ODBC и т.п. Однако, нет реализации интерфейса, поддерживающего взаимодействие клиента с сервером СУБД при помощи Pipe под Windows.

Таким образом, целью курсового проекта является разработка API взаимодействия клиентских приложений с сервером СУБД через Pipe под Windows.

Учитывая специфику выбранной СУБД и требование к реализации поддержки Pipe, приходится использовать трехзвенную модель взаимодействия клиентского приложения с СУБД. В выбранной модели запрос от клиентского приложения поступает в сервис среднего звена, который, обработав запрос, передает его на выполнение в СУБД SQLite. Результат также обрабатывается сервисом среднего звена, после чего передается клиенту.

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

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

В качестве преимущества выбранной модели можно отметить возможность контроля доступа и модификации данных. Также есть возможность ввести шифрование передающихся данных. Еще одним преимуществом трехзвенной архитектуры является возможность увеличить производительность БД за счет введения собственных методов кэширования.

Описание SQLite

Устройство и характеристики СУБД SQLite

СУБД SQLite является встраиваемой реляционной базой данных. SQLite не использует парадигму клиент-сервер, то есть SQLite не является отдельно работающим процессом, с которым взаимодействует программа, а предоставляет библиотеку, с которой программа компонуется и движок становится составной частью программы. Таким образом, в качестве протокола обмена используются вызовы функций (API) библиотеки SQLite. Такой подход уменьшает накладные расходы, время отклика и упрощает программу.очень тщательно тестируется перед каждым выпуском новой версии. Данная СУБД устойчива к «утечкам памяти» и ошибкам дискового ввода/вывода. доступна в исходных кодах (на языке C), использовать готовую DLL или в виде утилиты для командной строки.

Доступ к БД происходит через «подключения» к БД, который открывается через вызов соответствующей функции DLL. При открытии указывается имя файла БД. Если такого нету - он автоматически создается.

Допустимо открывать множество подключений к одной и тоже БД (через имя файла) в одном или разных приложениях. Система использует механизмы блокировки доступа к файлу на уровне ОС.может быть собрана в однопоточном варианте (параметр компиляции SQLITE_THREADSAFE = 0). В этом случае нельзя одновременно использовать несколько потоков, поскольку полностью отсутствует код синхронизации. Однако, в таком случае повышается производительность за счет экономии на алгоритмах синхронизации.

Проверить, есть ли многопоточность можно через вызов sqlite3_threadsafe(): если вернула 0, то это однопоточный SQLite.

По умолчанию, SQLite собран с поддержкой потоков (sqlite3.dll).

Есть два способа использования многопоточного SQLite: serialized и multi-thread.(надо указать флаг SQLITE_OPEN_FULLMUTEX при открытии соединения). В этом режиме потоки могут как угодно дергать вызовы SQLite, никаких ограничений. Но все вызовы блокируют друг друга и обрабатываются строго последовательно.

Multi-thread (SQLITE_OPEN_NOMUTEX). В этом режиме нельзя использовать одно и то же соединение одновременно из нескольких потоков (но допускается одновременное использование разных соединений разными потоками). Обычно используется именно этот режим.

Важной особенностью транзакционных баз данных, таких как SQLite является "атомарная транзакция". Это означает, что либо все изменения в базе данных в рамках одной транзакции вступают в силу, либо ни один из них не происходит. Так как, из-за физических ограничений, нельзя одновременно проводить запись в разные участки файла, механизм транзакций создает иллюзияю, что все операции, относящиеся в разные участки файла базы данных происходят мгновенно и одновременно.

В случае возникновения сбоя, вызванного отключением питания или сбоем системы, СУБД SQLite способна вернуть прежнее состояние базы данных до начала совершения транзакции.

Методы работы с базой данных

Для взаимодействия с базой данных SQLite используются стандартный набор функций, описанных в Windows DLL файле, поставляемом с БД. Также можно использовать отдельные модули, в которых реализованы функции под конкретный framework и язык программирования.

Основной задачей СУБД SQLite является оценка и выполнение полученного SQL запроса. Для подключения к СУБД в программе требуется иметь 2 объекта:

Объект соединения (database connection object);

Подготовленный объект оператора (prepared statement object).

Объект подключения и оператора обрабатываются небольшим набором функций из C/C++ интерфейса:

sqlite3_open();_prepare();_step();_column();_finalize();_close().

Для исполнения SQL выражения приложение должно выполнить следующие шаги:

Создание подготовленного оператора, используя sqlite3_prepare().

Выполнение подготовленного оператора, используя sqlite3_step(), один или несколько раз.

Для запросов извлечение результатов, используя sqlite3_column () между двумя вызовами sqlite3_step ().

Уничтожение подготовленного оператора путем вызова sqlite3_finalize().

Функция sqlite3_exec() является традиционным обработчиком, которым может заменить изложенные ранее 4 шага путем вызова одной функции. После выполнение вызывается callback функция, которая обрабатывает результат запроса.

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

Описание PIPE под Windows

Общие понятия

В операционных системах Microsoft Windows для передачи данных между процессами используются каналы PIPE. Это средство позволяет организовать передачу данных между локальными процессами, а также между процессами, запущенными на различных рабочих станциях в сети. Существуют две разновидности каналов Pipe - именованные (Named Pipes) и анонимные (Anonymous Pipes). Именованным каналам при создании присваивается имя, которое доступно для других процессов. Зная имя какой-либо рабочей станции в сети, процесс может получить доступ к каналу, созданному на этой рабочей станции. Анонимные каналы обычно используются для организации передачи данных между родительскими и дочерними процессами, запущенными на одной рабочей станции или на “отдельно стоящем” компьютере.

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

Именованные каналыPipe представляет собой канал для взаимодействия одного сервера и нескольких клиентов, подключаемых к нему по имени канала. Все клиенты подключаются по одному и тому же имени, на для каждого клиента создаются свои буферы и маркеры, и предоставляет отдельный канал для связи клиент - сервер. Такой подход позволяет использовать одновременно нескольким клиентам один и тот же канал. Если один серверный процесс использует несколько реализаций канала для связи с несколькими клиенсткими, то общее количество реализаций может быть меньше, чем потенциальное максимальное количество клиентов. Это связано с тем, что клиенты могут использовать реализации по очереди, если только они не пожелают связаться с серверным процессом все одновременно.

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

Именованные каналы не существуют постоянно, то есть не могут, в отличии от реализации pipe в Unix, быть созданы как специальные файлы. В ОС Windows имеют временные имена, которые автоматически могут быть уничтожены самой операционной системой после закрытия последней ссылки на канал.

Имена каналов в общем случае имеют следующий вид:

\\ИмяСервера\pipe\ИмяКанала

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

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

Методы WinAPI для передачи данных

Передача данных в именованный канал идет как при работе с файлом.

Канал Pipe может быть ориентирован либо на передачу потока байт, либо на передачу сообщений. В первом случае данные через канал передаются по байтам, во втором - отдельными блоками заданной длины. При создании канала можно определить, будет канал использоваться для чтения, записи или для чтения и записи.

Сервер не должен вызывать блокировку канала, пока клиент не закончит чтение / запись. В противном случае может возникнуть состояние гонки, что приведет к непредсказуемым результатам.

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

Для осуществления межпроцессного взаимодействия используются такие функции WinAPI как:

Для создания именованного канал вызывается функция CreateNamedPipe:

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_ATTRIBUTES lpSecurityAttributes

);

Для ожидания подключения клиента на сервере вызывается функция ConnectNamedPipe:

BOOL WINAPI ConnectNamedPipe(

_In_ HANDLE hNamedPipe,

_Inout_opt_ LPOVERLAPPED lpOverlapped

);

Для записи канал инициализируется подобно фалу, то есть используется функция CreateFile:

HANDLE WINAPI CreateFile(lpFileName,

_In_ DWORD dwDesiredAccess,

_In_ DWORD dwShareMode,

_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,

_In_ DWORD dwCreationDisposition,

_In_ DWORD dwFlagsAndAttributes,

_In_opt_ HANDLE hTemplateFile

);

Для передачи данных в канал используется функция WriteFile:

BOOL WINAPI WriteFile(

_In_ HANDLE hFile,

_In_ LPCVOID lpBuffer,

_In_ DWORD nNumberOfBytesToWrite,

_Out_opt_ LPDWORD lpNumberOfBytesWritten,

_Inout_opt_ LPOVERLAPPED lpOverlapped

);

Чтение из канала производится функцией ReadFile:

BOOL WINAPI ReadFile(

_In_ HANDLE hFile,

_Out_ LPVOID lpBuffer,

_In_ DWORD nNumberOfBytesToRead,

_Out_opt_ LPDWORD lpNumberOfBytesRead,

_Inout_opt_ LPOVERLAPPED lpOverlapped

);

Закрытие канала производится функцией CloseHandle:

BOOL WINAPI CloseHandle(

_In_ HANDLE hObject

);

Замысел технического решения

Задача по реализации клиентского API к СУБД с помощью PIPE под Windows сводится к 2 основным этапам:

Реализация клиент-серверного API для взаимодействия при помощи PIPE;

Исполнение запроса от клиента на сервере СУБД.

В проекте реализованы SQL команды, не возвращающие ответ пользователю. То есть такие как Insert, Update, Delete и т.п. После исполнения клиент только получает либо ответ об успешном выполнении, либо информацию об ошибке.

Реализация взаимодействия через PIPE

Существует два вида каналов: именованные и анонимные. Анонимные используются для передачи между родительским и дочерним приложением. Так как в данном проекте используются независимые сервер и клиент, анонимные каналы использовать не представляется возможным.

Поэтому для передачи SQL запроса с клиентского приложения на сервер, где находится СУБД SQLite, используется метод взаимодействия при помощи именованных каналов. При запуске сервера создается именованные канал. После по названию канала клиентское приложение связывается с сервером

Так как с сервером взаимодействует несколько клиентских приложений, возникает проблема идентификации каждого клиента в канале. Для этого используется буферы и маркеры для каждого клиентского приложения.

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

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

Для взаимодействия клиентского и серверного приложения требуются следующие функции:

Подключение клиента к серверу;

Передача строки запроса, введенной в клиентском приложении пользователем;

Прием ответа от сервера о результате исполнения или о возникших ошибках;

Отключение клиента от сервера.

Исполнение запросов к SQLite

Во время запуска сервера происходит подключение к СУБД. При подключении создается дескриптор подключения, за счет которого выполнятся все запросы к базе данных.

Так как сервер многопоточный, дескриптор подключения должен быть доступен всем потокам. Синхронизация доступа и блокировки реализованы в СУБД SQLite, поэтому достаточно отправить запрос на выполнение.

После исполнения запроса проводится проверка на возникшие ошибки. Если произошла ошибка, то информация о ней передается на клиент а СУБД никаких изменений в базу данных не вносит.

В случае успешного выполнения запроса клиенту передается ответ об успешном выполнении, а на сервере управление переходит к вызвавшему потоку.

Описание программы

Сервер

При запуске сервера создается именованный канал с именем \\.\\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 Происходит передача запроса на сервер, его исполнение и возврат результата.

После исполнения запроса клиент прекращает свою работу.

API

Для взаимодействия с сервером реализован класс Pipe_SERVER, исходный код которого находится в файле «SQLite_API.h» и представлен в Приложении. Функции в API:connect() - функция для подключения к серверу. Возвращает 0, если подключение прошло успешно. В случае ошибки происходит вывод текста ошибки и функция возвращает 1. send_data(wchar_t *chRequest, int length) - функция для передачи строки запроса chRequest длиной length. В случае успешной передачи возвращает 0. Иначе возвращает 1 и отключает от сервера.recieve_data() - функция, предназначенная для получения ответа от сервера. Возвращает 0 в случае успешного исполнения. В случае ошибки возвращает 0 и отключает от сервера.cleanup() - функция для отключения от сервера.

Для использования функция 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.

Список используемой литературы

Программирование для Windows NT. - Александр Фролов, Григорий фролов. Том 27, часть 2. М.: Диалог-МИФИ, 1996

Системы баз данных. Полный курс. - Гарсиа-Молина Г.,Ульман Дж., Уидом Дж. Вильямс, 2003.-1088с.

C++ для профессионалов. - Николас А. Солтер, Майкл Л. Клепер <http://www.ozon.ru/person/1372373/>. Диалектика <http://www.ozon.ru/brand/856497/>, Вильямс <http://www.ozon.ru/brand/856490/>, 2006SQLite. - Jay A. Kreibich - O'Reilly Media 2010

Приложение 1

CppNamedPipeServer.cpp

#include <windows.h>

#include <stdio.h>

#include <tchar.h>

#include <strsafe.h>

#include "iostream"

#include <string>

#include "atlstr.h"

#include "sqlite3.h"

#define BUFSIZE 512namespace std;WINAPI InstanceThread(LPVOID); GetAnswerToRequest(LPTSTR, LPTSTR, LPDWORD);

sqlite3 *db = 0; // хэндл объекта соединение к БД

char *err = 0;_tmain(VOID)

{ fConnected = FALSE; dwThreadId = 0; hPipe = INVALID_HANDLE_VALUE, hThread = NULL; lpszPipename = TEXT("\\\\.\\pipe\\SamplePipe"); ( sqlite3_open("db1.dblite", &db) )("Error in open/create DB: %s\n", sqlite3_errmsg(db));(;;)

{

_tprintf( TEXT("\nPipe Server: Main thread awaiting client connection on %s\n"), lpszPipename);= CreateNamedPipe( , // pipe name _ACCESS_DUPLEX, // read/write access _TYPE_MESSAGE | // message type pipe _READMODE_MESSAGE | // message-read mode _WAIT, // blocking mode _UNLIMITED_INSTANCES, // max. instances , // output buffer size , // input buffer size

, // client time-out ); // default security attribute (hPipe == INVALID_HANDLE_VALUE)

{

_tprintf(TEXT("CreateNamedPipe failed, GLE=%d.\n"), GetLastError()); -1;

}

fConnected = ConnectNamedPipe(hPipe, NULL) ? : (GetLastError() == ERROR_PIPE_CONNECTED);

if (fConnected)

{ ("Client connected, creating a processing thread.\n");

// Create a thread for this client. = CreateThread( , // no security attribute

, // default stack size , // thread proc

(LPVOID) hPipe, // thread parameter

, // not suspended

{

_tprintf(TEXT("CreateThread failed, GLE=%d.\n"), GetLastError()); -1;

}CloseHandle(hThread);

}

// The client could not connect, so close the pipe. (hPipe);

} 0;

} WINAPI InstanceThread(LPVOID lpvParam)

{ hHeap = GetProcessHeap();* pchRequest = (TCHAR*)HeapAlloc(hHeap, 0, BUFSIZE*sizeof(TCHAR));* pchReply = (TCHAR*)HeapAlloc(hHeap, 0, BUFSIZE*sizeof(TCHAR));cbBytesRead = 0, cbReplyBytes = 0, cbWritten = 0; fSuccess = FALSE;hPipe = NULL;(lpvParam == NULL)

{( "\nERROR - Pipe Server Failure:\n");( " InstanceThread got an unexpected NULL value in lpvParam.\n");( " InstanceThread exitting.\n");(pchReply != NULL) HeapFree(hHeap, 0, pchReply);(pchRequest != NULL) HeapFree(hHeap, 0, pchRequest);(DWORD)-1;

}(pchRequest == NULL)

{( "\nERROR - Pipe Server Failure:\n");( " InstanceThread got an unexpected NULL heap allocation.\n");( " InstanceThread exitting.\n");(pchReply != NULL) HeapFree(hHeap, 0, pchReply);(DWORD)-1;

}(pchReply == NULL)

{( "\nERROR - Pipe Server Failure:\n");( " InstanceThread got an unexpected NULL heap allocation.\n");( " InstanceThread exitting.\n");(pchRequest != NULL) HeapFree(hHeap, 0, pchRequest);(DWORD)-1;

}

// Print verbose messages. In production code, this should be for debugging only.("InstanceThread created, receiving and processing messages.\n");

= (HANDLE) lpvParam;

// Loop until done reading(1)

{ = ReadFile( , // handle to pipe , // buffer to receive data *sizeof(TCHAR), // size of buffer

&cbBytesRead, // number of bytes read ); // not overlapped I/O (!fSuccess || cbBytesRead == 0)

{ (GetLastError() == ERROR_BROKEN_PIPE)

{

_tprintf(TEXT("InstanceThread: client disconnected.\n"), GetLastError());

}

{

_tprintf(TEXT("InstanceThread ReadFile failed, GLE=%d.\n"), GetLastError());

};

}

// Process the incoming message.(pchRequest, pchReply, &cbReplyBytes);

// Write the reply to the pipe. = WriteFile( , // handle to pipe , // buffer to write from , // number of bytes to write

&cbWritten, // number of bytes written ); // not overlapped I/O (!fSuccess || cbReplyBytes != cbWritten)

{

_tprintf(TEXT("InstanceThread WriteFile failed, GLE=%d.\n"), GetLastError()); ;

}

}

FlushFileBuffers(hPipe); (hPipe); (hPipe); (hHeap, 0, pchRequest);(hHeap, 0, pchReply);("InstanceThread exitting.\n");1;

}GetAnswerToRequest( wchar_t* pchRequest, pchReply, pchBytes )

{

_tprintf( TEXT("Client Request String:\"%s\"\n"), pchRequest );<< pchRequest << _T(" (wchar_t *)") << endl;_t origsize = wcslen(pchRequest) + 1;_t convertedChars = 0;size_t newsize = origsize*2;*sqlreq = new char[newsize];_s(&convertedChars, sqlreq, newsize, pchRequest, _TRUNCATE);<<"SQL request: "<< sqlreq << endl;_t *response;= L" ";(sqlite3_exec(db, sqlreq, 0, 0, &err))

{("SQL Error: %sn", err);_free(err);= L"SQL Error";

} else response = L"Success";

// Check the outgoing message to make sure it's not too long for the buffer.(FAILED(StringCchCopy( pchReply, BUFSIZE, response )))

{

*pchBytes = 0;[0] = 0;("StringCchCopy failed, no outgoing message.\n");;

}

*pchBytes = (lstrlen(pchReply)+1)*sizeof(TCHAR);

}

Приложение 2

CppNamedPipeClient.cpp

#pragma region Includes

#include <stdio.h>

#include <windows.h>

#include "iostream"

#pragma endregion

#include "SQLite_API.h"

// The full name of the pipe in the format of \\servername\pipe\pipename.

#define SERVER_NAME L"."

#define PIPE_NAME L"SamplePipe"

#define FULL_PIPE_NAME L"\\\\" SERVER_NAME L"\\pipe\\" PIPE_NAME

#define BUFFER_SIZE 1024

// Request message from client to server.

#define REQUEST_MESSAGE L"CREATE TABLE IF NOT EXISTS foo(a,b,c); INSERT INTO FOO VALUES(1,2,3); INSERT INTO FOO SELECT * FROM FOO;"namespace std;wmain(int argc, wchar_t* argv[])

{_t req_str[200];_SERVER server(FULL_PIPE_NAME);

// Try to open the named pipe identified by the pipe name.err = server.connect();(err == 1) { << "Error while connection";.cleanup();("pause");0;

}(L"Enter Request:");( L"%[^\r\n]", req_str );

//

// Send a request from client to server

// (server.send_data(req_str, sizeof(req_str)) !=0 ) {<< "error while sending data";.cleanup();("pause");0;

} else {<< "Success in sending"<<endl;

}

//

//

//

//Code from exhample(server.recieve_data() == 0)(L"Recieved successfull. Data: \"%s\"\n", server.chResponse);

//.cleanup();("pause");server.dwError;

}

Приложение 3

SQLite_API.h

#include <stdio.h>

#include <windows.h>

#include "iostream"

#pragma endregionPipe_SERVER

{:hPipe;FULL_PIPE_NAME;const int BUFFER_SIZE = 1024;:dwError;chResponse[BUFFER_SIZE]; //Answers from server_SERVER(LPCWSTR PIPE_NAME){= INVALID_HANDLE_VALUE;= ERROR_SUCCESS;_PIPE_NAME = PIPE_NAME;

}connect(){(TRUE){= CreateFile( _PIPE_NAME, // Pipe name _READ | GENERIC_WRITE, // Read and write access

, // No sharing , // Default security attributes_EXISTING, // Opens existing pipe

, // Default attributes// No template file

);(hPipe != INVALID_HANDLE_VALUE)

{(L"The named pipe (%s) is connected.\n", FULL_PIPE_NAME);;

}= GetLastError();(ERROR_PIPE_BUSY != dwError)

{(L"Unable to open named pipe w/err 0x%08lx\n", dwError);1;

}

// All pipe instances are busy, so wait for 5 seconds.(!WaitNamedPipe(FULL_PIPE_NAME, 5000))

{= GetLastError();(L"Could not open pipe: 5 second wait timed out.");1;

}

}

// Set the read mode and the blocking mode of the named pipe. In this

// sample, we set data to be read from the pipe as a stream of messages.dwMode = PIPE_READMODE_MESSAGE;(!SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL))

{= GetLastError();(L"SetNamedPipeHandleState failed w/err 0x%08lx\n", dwError);0;

}0;

}

//send_data(wchar_t *chRequest, int length){cbWritten;( L"Sizeof %d of message: %s\n",length, chRequest);

;(!WriteFile(, // Handle of the pipe, // Message to be written, // Number of bytes to write

&cbWritten, // Number of bytes written// Not overlapped

))

{= GetLastError();(L"WriteFile to pipe failed w/err 0x%08lx\n", dwError);1;();

}(L"Send %ld bytes to server: \"%s\"\n", cbWritten, chRequest);0;

}recieve_data(){fFinishRead = FALSE;

{cbResponse, cbRead;= sizeof(chResponse);= ReadFile(, // Handle of the pipe, // Buffer to receive the reply, // Size of buffer in bytes

&cbRead, // Number of bytes read // Not overlapped

);(!fFinishRead && ERROR_MORE_DATA != GetLastError())

{= GetLastError();(L"ReadFile from pipe failed w/err 0x%08lx\n", dwError);();1;

}

} while (!fFinishRead); // Repeat loop if ERROR_MORE_DATA0;

}cleanup(){

// Centralized cleanup for all allocated resources.(hPipe != INVALID_HANDLE_VALUE)

{(hPipe);= INVALID_HANDLE_VALUE;

}::cout << "Cleanup";

}

};

Похожие работы на - API взаимодействия клиентских приложений с сервером СУБД

 

Не нашли материал для своей работы?
Поможем написать уникальную работу
Без плагиата!