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

Заключение

В заключение следует сделать вывод, что использование Pipe на ОС Windows упрощает разработку различных клиент-серверных приложений. Засчет того, что в Pipe используются такие же методы WinAPI, как и для работы с файлами, время разработки существенно сокращается.

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

Данный интерфейс не требует привязки к определенной СУБД так как передается только SQL запрос. А сами алгоритмы работы с СУБД реализованы на стороне сервера. Есть возможность использовать на сервере любой интерфейс для работы с СУБД.

С помощью разработанного API появляется возможность использования БД не на локальном компьютере, а на сервере в локальной сети. Для этого требуется только задать требуемое имя канала.

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

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

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

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

C++ для профессионалов. - Николас А. Солтер, Майкл Л. Клепер. Диалектика, Вильямс, 2006

Using SQLite. - Jay A. Kreibich - OReilly 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 512

using namespace std;

DWORD WINAPI InstanceThread(LPVOID);

VOID GetAnswerToRequest(LPTSTR, LPTSTR, LPDWORD);

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

char *err = 0;

int _tmain(VOID)

{

BOOL fConnected = FALSE;

DWORD dwThreadId = 0;

HANDLE hPipe = INVALID_HANDLE_VALUE, hThread = NULL;

LPTSTR lpszPipename = TEXT("\.pipeSamplePipe");

if( sqlite3_open("db1.dblite", &db) )

printf("Error in open/create DB: %s ", sqlite3_errmsg(db));

for (;;)

{

_tprintf( TEXT(" Pipe Server: Main thread awaiting client connection on %s "), lpszPipename);

hPipe = CreateNamedPipe(

lpszPipename, // pipe name

PIPE_ACCESS_DUPLEX, // read/write access

PIPE_TYPE_MESSAGE | // message type pipe

PIPE_READMODE_MESSAGE | // message-read mode

PIPE_WAIT, // blocking mode

PIPE_UNLIMITED_INSTANCES, // max. instances

BUFSIZE, // output buffer size

BUFSIZE, // input buffer size

0, // client time-out

NULL); // default security attribute

if (hPipe == INVALID_HANDLE_VALUE)

{

_tprintf(TEXT("CreateNamedPipe failed, GLE=%d. "), GetLastError());

return -1;

}

fConnected = ConnectNamedPipe(hPipe, NULL) ?

TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);

if (fConnected)

{

printf("Client connected, creating a processing thread. ");

// Create a thread for this client.

hThread = CreateThread(

NULL, // no security attribute

0, // default stack size

InstanceThread, // thread proc

(LPVOID) hPipe, // thread parameter

0, // not suspended

&dwThreadId); // returns thread ID

if (hThread == NULL)

{

_tprintf(TEXT("CreateThread failed, GLE=%d. "), GetLastError());

return -1;

}

else CloseHandle(hThread);

}

else

// The client could not connect, so close the pipe.

CloseHandle(hPipe);

}

return 0;

}

DWORD WINAPI InstanceThread(LPVOID lpvParam)

{

HANDLE hHeap = GetProcessHeap();

TCHAR* pchRequest = (TCHAR*)HeapAlloc(hHeap, 0, BUFSIZE*sizeof(TCHAR));

TCHAR* pchReply = (TCHAR*)HeapAlloc(hHeap, 0, BUFSIZE*sizeof(TCHAR));

DWORD cbBytesRead = 0, cbReplyBytes = 0, cbWritten = 0;

BOOL fSuccess = FALSE;

HANDLE hPipe = NULL;

if (lpvParam == NULL)

{

printf( " ERROR - Pipe Server Failure: ");

printf( " InstanceThread got an unexpected NULL value in lpvParam. ");

printf( " InstanceThread exitting. ");

if (pchReply != NULL) HeapFree(hHeap, 0, pchReply);

if (pchRequest != NULL) HeapFree(hHeap, 0, pchRequest);

return (DWORD)-1;

}

if (pchRequest == NULL)

{

printf( " ERROR - Pipe Server Failure: ");

printf( " InstanceThread got an unexpected NULL heap allocation. ");

printf( " InstanceThread exitting. ");

if (pchReply != NULL) HeapFree(hHeap, 0, pchReply);

return (DWORD)-1;

}

if (pchReply == NULL)

{

printf( " ERROR - Pipe Server Failure: ");

printf( " InstanceThread got an unexpected NULL heap allocation. ");

printf( " InstanceThread exitting. ");

if (pchRequest != NULL) HeapFree(hHeap, 0, pchRequest);

return (DWORD)-1;

}

// Print verbose messages. In production code, this should be for debugging only.

printf("InstanceThread created, receiving and processing messages. ");

hPipe = (HANDLE) lpvParam;

// Loop until done reading

while (1)

{

fSuccess = ReadFile(

hPipe, // handle to pipe

pchRequest, // buffer to receive data

BUFSIZE*sizeof(TCHAR), // size of buffer

&cbBytesRead, // number of bytes read

NULL); // not overlapped I/O

if (!fSuccess || cbBytesRead == 0)

{

if (GetLastError() == ERROR_BROKEN_PIPE)

{

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

}

else

{

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

}

break;

}

// Process the incoming message.

GetAnswerToRequest(pchRequest, pchReply, &cbReplyBytes);

// Write the reply to the pipe.

fSuccess = WriteFile(

hPipe, // handle to pipe

pchReply, // buffer to write from

cbReplyBytes, // number of bytes to write

&cbWritten, // number of bytes written

NULL); // not overlapped I/O

if (!fSuccess || cbReplyBytes != cbWritten)

{

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

break;

}

}

FlushFileBuffers(hPipe);

DisconnectNamedPipe(hPipe);

CloseHandle(hPipe);

HeapFree(hHeap, 0, pchRequest);

HeapFree(hHeap, 0, pchReply);

printf("InstanceThread exitting. ");

return 1;

}

VOID GetAnswerToRequest( wchar_t* pchRequest,

LPTSTR pchReply,

LPDWORD pchBytes )

{

_tprintf( TEXT("Client Request String:"%s" "), pchRequest );

wcout << pchRequest << _T(" (wchar_t *)") << endl;

size_t origsize = wcslen(pchRequest) + 1;

size_t convertedChars = 0;

const size_t newsize = origsize*2;

char *sqlreq = new char[newsize];

wcstombs_s(&convertedChars, sqlreq, newsize, pchRequest, _TRUNCATE);

cout <<"SQL request: "<< sqlreq << endl;

wchar_t *response;

response = L" ";

if (sqlite3_exec(db, sqlreq, 0, 0, &err))

{

printf("SQL Error: %sn", err);

sqlite3_free(err);

response = L"SQL Error";

} else response = L"Success";

// Check the outgoing message to make sure its not too long for the buffer.

if (FAILED(StringCchCopy( pchReply, BUFSIZE, response )))

{

*pchBytes = 0;

pchReply[0] = 0;

printf("StringCchCopy failed, no outgoing message. ");

return;

}

*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 servernamepipepipename.

#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;"

using namespace std;

int wmain(int argc, wchar_t* argv[])

{

wchar_t req_str[200];

Pipe_SERVER server(FULL_PIPE_NAME);

// Try to open the named pipe identified by the pipe name.

int err = server.connect();

if (err == 1) {

cout << "Error while connection";

server.cleanup();

system("pause");

return 0;

}

wprintf(L"Enter Request:");

wscanf( L"%[^ ]", req_str );

//

// Send a request from client to server

//

if (server.send_data(req_str, sizeof(req_str)) !=0 ) {

cout << "error while sending data";

server.cleanup();

system("pause");

return 0;

} else {

cout << "Success in sending"<<endl;

}

//

// Receive a response from server.

//

//

//Code from exhample

if (server.recieve_data() == 0)

wprintf(L"Recieved successfull. Data: "%s" ", server.chResponse);

//

server.cleanup();

system("pause");

return server.dwError;

}

Приложение 3

SQLite_API.h

#include <stdio.h>

#include <windows.h>

#include "iostream"

#pragma endregion

class Pipe_SERVER

{

private:

HANDLE hPipe;

LPCWSTR FULL_PIPE_NAME;

static const int BUFFER_SIZE = 1024;

public:

DWORD dwError;

TCHAR chResponse[BUFFER_SIZE]; //Answers from server

Pipe_SERVER(LPCWSTR PIPE_NAME){

hPipe = INVALID_HANDLE_VALUE;

dwError = ERROR_SUCCESS;

FULL_PIPE_NAME = PIPE_NAME;

}

int connect(){

while (TRUE){

hPipe = CreateFile(

FULL_PIPE_NAME, // Pipe name

GENERIC_READ | GENERIC_WRITE, // Read and write access

0, // No sharing

NULL, // Default security attributes

OPEN_EXISTING, // Opens existing pipe

0, // Default attributes

NULL // No template file

);

if (hPipe != INVALID_HANDLE_VALUE)

{

wprintf(L"The named pipe (%s) is connected. ", FULL_PIPE_NAME);

break;

}

dwError = GetLastError();

if (ERROR_PIPE_BUSY != dwError)

{

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

return 1;

}

// All pipe instances are busy, so wait for 5 seconds.

if (!WaitNamedPipe(FULL_PIPE_NAME, 5000))

{

dwError = GetLastError();

wprintf(L"Could not open pipe: 5 second wait timed out.");

return 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.

DWORD dwMode = PIPE_READMODE_MESSAGE;

if (!SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL))

{

dwError = GetLastError();

wprintf(L"SetNamedPipeHandleState failed w/err 0x%08lx ", dwError);

return 0;

}

return 0;

}

//

int send_data(wchar_t *chRequest, int length){

DWORD cbWritten;

wprintf( L"Sizeof %d of message: %s ",length, chRequest);

;

if (!WriteFile(

hPipe, // Handle of the pipe

chRequest, // Message to be written

length, // Number of bytes to write

&cbWritten, // Number of bytes written

NULL // Not overlapped

))

{

dwError = GetLastError();

wprintf(L"WriteFile to pipe failed w/err 0x%08lx ", dwError);

return 1;

cleanup();

}

wprintf(L"Send %ld bytes to server: "%s" ", cbWritten, chRequest);

return 0;

}

int recieve_data(){

BOOL fFinishRead = FALSE;

do

{

DWORD cbResponse, cbRead;

cbResponse = sizeof(chResponse);

fFinishRead = ReadFile(

hPipe, // Handle of the pipe

chResponse, // Buffer to receive the reply

cbResponse, // Size of buffer in bytes

&cbRead, // Number of bytes read

NULL // Not overlapped

);

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

{

dwError = GetLastError();

wprintf(L"ReadFile from pipe failed w/err 0x%08lx ", dwError);

cleanup();

return 1;

}

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

return 0;

}

void cleanup(){

// Centralized cleanup for all allocated resources.

if (hPipe != INVALID_HANDLE_VALUE)

{

CloseHandle(hPipe);

hPipe = INVALID_HANDLE_VALUE;

}

std::cout << "Cleanup";

}

};