Заключение
В заключение следует сделать вывод, что использование 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";
}
};
- Исследование предметной области
- Постановка задачи
- Описание SQLite
- Устройство и характеристики СУБД SQLite
- Методы работы с базой данных
- Описание PIPE под Windows
- Общие понятия
- Именованные каналы
- Методы WinAPI для передачи данных
- Замысел технического решения
- Реализация взаимодействия через PIPE
- Исполнение запросов к SQLite
- Описание программы
- Сервер
- Клиент
- API
- Заключение