sqlbackupservice.cpp
来自「我写的SQL Server网络备份工具。(服务器端用VC开发」· C++ 代码 · 共 640 行
CPP
640 行
#include <memory>
#include "StdAfx.h"
#include ".\sqlbackupservice.h"
#include "Message.h"
#define MESSAGE_BUFF_SIZE 500
#define BUFFER_SIZE 10240
using namespace std;
class InitCom
{
public:
InitCom()
{
m_bInitSucceed = SUCCEEDED(CoInitialize(NULL));
}
~InitCom()
{
if(m_bInitSucceed)
::CoUninitialize();
}
BOOL operator ! ()
{
return !m_bInitSucceed;
}
protected:
BOOL m_bInitSucceed;
};
class PChar
{
public:
PChar():m_pStr(NULL){}
PChar(char *p)
{
_ASSERT(p);
m_pStr = p;
}
~PChar()
{
if(m_pStr)
delete []m_pStr;
}
void Attach(char *p)
{
if(m_pStr)
delete []m_pStr;
m_pStr = p;
}
operator char * ()
{
return m_pStr;
}
protected:
char *m_pStr;
};
int sendn(SOCKET sock , char *pBuff , int len)
{
int nSendLength , nSize;
nSize = len;
while(nSize > 0)
{
nSendLength = send(sock , pBuff , nSize , 0);
if(nSendLength < 0)
{
return -1;
}
if(nSendLength == 0)
{
return len - nSize;
}
nSize -= nSendLength;
pBuff += nSendLength;
}
return len;
}
int readn(SOCKET sock , char *pBuff , int len)
{
int nSize = len;
int nReadLength;
while(nSize > 0)
{
nReadLength = recv(sock , pBuff , nSize , 0);
if(nReadLength < 0)
{
return -1;
}
if(nReadLength == 0)
{
return len - nSize;
}
nSize -= nReadLength;
pBuff += nReadLength;
}
return len;
}
BOOL CheckCreateDir(const CString &strPath)
{
_ASSERT(strPath.GetLength());
CString strDir;
if(strPath.GetAt(strPath.GetLength() - 1) == '\\')
{
strDir = strPath.Left( strPath.GetLength() - 1);
}
else
{
strDir = strPath;
}
WIN32_FIND_DATA wfd;
HANDLE hFind = FindFirstFile(strDir , &wfd);
if(hFind == INVALID_HANDLE_VALUE)
{
return CreateDirectory(strDir , NULL);
}
BOOL bExistOrSucceed = FALSE;
if(wfd.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY)
{
bExistOrSucceed = TRUE;
}
else
{
bExistOrSucceed = CreateDirectory(strDir , NULL);
}
FindClose(hFind);
return bExistOrSucceed;
}
class CInitSocket
{
public:
CInitSocket()
{
m_bInitSucceed = (WSAStartup(MAKEWORD(2,2) ,&m_wsaData) == 0);
}
~CInitSocket()
{
if(m_bInitSucceed)
{
WSACleanup();
}
}
BOOL operator ! ()
{
return !m_bInitSucceed;
}
operator WSADATA * ()
{
return &m_wsaData;
}
protected:
WSADATA m_wsaData;
BOOL m_bInitSucceed;
};
void CSQLBackupService::OutputMessageToFile(char * pMessage)
{
char PathBuff[MESSAGE_BUFF_SIZE];
char MsgBuff[MESSAGE_BUFF_SIZE];
CTime CurDate(CTime::GetCurrentTime());
strcpy(PathBuff , m_szAppPath);
strcat(PathBuff , "RuntimeError.txt");
sprintf(MsgBuff , "%s %d-%d-%d.\n" , pMessage , CurDate.GetYear() , CurDate.GetMonth() , CurDate.GetDay());
OutputMessage(PathBuff , MsgBuff);
}
CSQLBackupService::CSQLBackupService(void)
:CNTService(TEXT("SQLBackupService"))
{
::GetModuleFileName(NULL , m_szAppName , _MAX_PATH);
TCHAR *pFind , *pLastPos;
for(pFind = pLastPos = m_szAppName; *pFind ; pFind++)
{
if(*pFind == '\\')
{
pLastPos = pFind;
pLastPos++;
}
}
int iLength = (pLastPos - m_szAppName)/(int)sizeof(TCHAR);
_tcsncpy(m_szAppPath , m_szAppName , iLength);
m_szAppPath[iLength] = '\0';
}
CSQLBackupService::~CSQLBackupService(void)
{
}
void CSQLBackupService::Run(void)
{
CInitSocket _InitSocket;
if(!_InitSocket)
{
OutputMessageToFile("Could't Initialize Ws2_32.dll");
}
{
SOCKET sockListen;
if((sockListen = socket(AF_INET , SOCK_STREAM , IPPROTO_IP)) == INVALID_SOCKET)
{
OutputMessageToFile("Could't create listen socket");
return;
}
m_sockListen.Attach(sockListen);
struct sockaddr_in sin;
memset(&sin , 0 , sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(1888);
sin.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
if(bind(m_sockListen , (struct sockaddr *) &sin , sizeof(sin)) == SOCKET_ERROR)
{
OutputMessageToFile("Could't bind socket");
return;
}
}
if(listen(m_sockListen , 5) == SOCKET_ERROR)
{
OutputMessageToFile("Could't listen socket");
return;
}
SOCKET sockClient;
HANDLE hThread;
while(m_bIsRunning)
{
if((sockClient = accept(m_sockListen , NULL , NULL)) == INVALID_SOCKET)
{
return;
}
hThread = CreateThread(NULL , 0 , ClientThread , (LPVOID)sockClient , 0 , NULL);
#ifdef _DEBUG
OutputMessageToFile("Create client listen thread");
#endif
Sleep(50);
if(hThread)
CloseHandle(hThread);
}
}
void CSQLBackupService::OnStop(void)
{
m_sockListen.Close();
}
DWORD WINAPI CSQLBackupService::ClientThread(LPVOID lpParam)
{
MySocket sockClient;
CSQLBackupService *pThis =(CSQLBackupService *) CSQLBackupService::m_pThis;
sockClient.Attach((SOCKET)lpParam);
//sockClient
#ifdef _DEBUG
pThis->OutputMessageToFile("Begin read data");
#endif
struct Request _request;
int nLenght;
nLenght = 60000;
setsockopt(sockClient , SOL_SOCKET , SO_RCVTIMEO , (char *)&nLenght , sizeof(int));
while(TRUE)
{
nLenght = readn(sockClient ,(char *) &_request , sizeof(_request));
#ifdef _DEBUG
CString temp;
temp.Format("read szie is %d < %d" , nLenght , sizeof(_request));
pThis->OutputMessageToFile((char *)(LPCSTR)temp);
#endif
if((int)nLenght < (int)sizeof(_request))
{
#ifdef _DEBUG
pThis->OutputMessageToFile("接受数据出错或客户端断开连接");
CString temp;
temp.Format("szie is %d" , nLenght);
pThis->OutputMessageToFile((char *)(LPCSTR)temp);
#endif
return 0;
}
#ifdef _DEBUG
pThis->OutputMessageToFile("接受客户端连接信息");
#endif
if(_request.sign != 0x7171)
{
#ifdef _DEBUG
pThis->OutputMessageToFile("客户端非法请求。");
#endif
return 0;
}
#ifdef _DEBUG
CString Temp;
Temp.Format("Request type is %d" , _request.type);
pThis->OutputMessageToFile((char *)(LPCSTR)Temp);
#endif
switch(_request.type)
{
case RT_CONNECT:
pThis->SendConnectSucceed(sockClient);
case RT_QUERYDATABASE:
#ifdef _DEBUG
pThis->OutputMessageToFile("客户端请求查询数据库");
#endif
pThis->ResponseQueryDatabase(sockClient);
break;
case RT_BACKUP:
pThis->ResponseBackup(sockClient , _request.size - sizeof(_request));
break;
default:
return 0;
}
Sleep(1000);
}
return 0;
}
void CSQLBackupService::ResponseBackup(MySocket &ClientSocket , int nParamLenght)
{
if(nParamLenght < 1)
{
SendErrorMessage(ClientSocket , "备份操作需要指定数据库名称。");
return ;
}
PChar pDatabase(new char[nParamLenght + 1]);
if(readn(ClientSocket , pDatabase , nParamLenght) != nParamLenght)
{
OutputMessageToFile("接受数据出错");
return;
}
//备份数据库
CTime CurDate(CTime::GetCurrentTime());
CString strFileName , strMsg;
strFileName.Format("%s%d%d%d%d%d%d.bak" , pDatabase , CurDate.GetYear() , CurDate.GetMonth() , CurDate.GetDay() ,
CurDate.GetHour() , CurDate.GetMinute() , CurDate.GetSecond());
strMsg = m_szAppPath + CString(TEXT("Backup"));
if(CheckCreateDir(strMsg) == FALSE)
{
strMsg = m_szAppPath;
}
strFileName = strMsg + '\\' + strFileName;
if(Backup(pDatabase , strFileName , strMsg) == FALSE)
{
SendErrorMessage(ClientSocket ,(char *)(LPCSTR)strMsg);
#ifdef _DEBUG
OutputMessageToFile("exit error.");
#endif
return;
}
//传送备份文件
Sleep(100);
SendFile(ClientSocket , strFileName);
}
void CSQLBackupService::SendErrorMessage(MySocket &ClientSocket, char * pMessage)
{
struct Response *pResponse;
int len;
_ASSERT(pMessage);
len = strlen(pMessage);
_ASSERT(len > 0);
len += sizeof(struct Response) + 1;
PChar pBuff(new char[len]);
pResponse = (struct Response *) (char *)pBuff;
pResponse->sign = 0x7171;
pResponse->type = RT_ERROR;
pResponse->size = len;
strcpy(pBuff + sizeof(struct Response) , pMessage);
if(sendn(ClientSocket , pBuff , len) != len)
{
OutputMessageToFile("网络传输错误");
}
}
BOOL CSQLBackupService::SendFile(MySocket& ClientSocket , const CString &strFileName)
{
struct Response _response;
long length , readlength;
//long size;
#ifdef _DEBUG
OutputMessageToFile("begin send file");
#endif
FILE *pFile;
pFile = fopen((LPCSTR)strFileName , "rb");
if(pFile == NULL)
{
char *str = "没有找到备份文件";
OutputMessageToFile(str);
SendErrorMessage(ClientSocket , str);
return FALSE;
}
fseek(pFile , 0L , SEEK_END);
length = ftell(pFile);
fseek(pFile , 0 , SEEK_SET);
_response.sign = 0x7171;
_response.type = RT_SUCCEED;
_response.size = sizeof(_response) + length;
PChar pBuff(new char[BUFFER_SIZE]);
if(sendn(ClientSocket , (char *)&_response , sizeof(_response)) != sizeof(_response))
{
OutputMessageToFile("网络传输错误");
fclose(pFile);
//ClientSocket.Close();
return FALSE;
}
while(length > 0)
{
if(length - BUFFER_SIZE >= 0)
readlength = BUFFER_SIZE;
else
readlength = length;
length -= readlength;
if( fread((char *)pBuff , readlength , 1 , pFile) == 0)
{
OutputMessageToFile("备份文件读取错误");
fclose(pFile);
//ClientSocket.Close();
return FALSE;
}
if(sendn(ClientSocket , pBuff , readlength) != readlength)
{
OutputMessageToFile("文件传输过程中出错");
fclose(pFile);
//ClientSocket.Close();
return FALSE;
}
}
fclose(pFile);
#ifdef _DEBUG
OutputMessageToFile("文件传送完毕");
#endif
return TRUE;
}
BOOL CSQLBackupService::Backup(const char *pDatabase ,const CString & strFileName , CString &strMsg)
{
InitCom _InitCom;
if(!_InitCom)
{
strMsg = "服务器初始化COM组件出错。";
return FALSE;
}
LPSQLDMOSERVER pSQLServer = NULL;
LPSQLDMOBACKUP pSQLBackup = NULL;
HRESULT hr;
#ifdef _DEBUG
this->OutputMessageToFile((char *)pDatabase);
#endif
if FAILED(hr = CoCreateInstance (CLSID_SQLDMOServer, NULL, CLSCTX_INPROC_SERVER,
IID_ISQLDMOServer, (LPVOID*)&pSQLServer))
{
strMsg = "不能初始化SQLDMOServer组件";
return FALSE;
}
if FAILED(hr = CoCreateInstance (CLSID_SQLDMOBackup, NULL, CLSCTX_INPROC_SERVER,
IID_ISQLDMOBackup, (LPVOID*)&pSQLBackup))
{
strMsg = "不能初始化SQLDMOBackup组件";
pSQLServer->Release();
return FALSE;
}
pSQLServer->SetLoginTimeout (30);
pSQLServer->SetLoginSecure (TRUE);
#ifdef _DEBUG
this->OutputMessageToFile("pSQLServer->SetLoginSecure (TRUE);");
#endif
if(FAILED(pSQLServer->Connect()))
{
strMsg = "不能连接到SQL数据库";
pSQLBackup->Release();
pSQLServer->Release();
return FALSE;
}
pSQLBackup->SetDatabase(CComBSTR(pDatabase));
pSQLBackup->SetFiles(CComBSTR(strFileName));
if( FAILED(hr = pSQLBackup->SQLBackup (pSQLServer)) )
{
strMsg = "数据备份没有成功。";
pSQLServer->DisConnect ();
pSQLBackup->Release();
pSQLServer->Release();
return FALSE;
}
pSQLServer->DisConnect ();
pSQLBackup->Release();
pSQLServer->Release();
return TRUE;
}
void CSQLBackupService::ResponseQueryDatabase(MySocket& sockClient)
{
long lNumDB;
long lCount;
BOOL bSystemObj = FALSE;
BSTR lpDBName;
LPSQLDMODATABASE pDatabase = NULL;
LPSQLDMODATABASES pDatabases = NULL;
InitCom _InitCom;
LPSQLDMOSERVER pSQLServer = NULL;
LPSQLDMOBACKUP pSQLBackup = NULL;
HRESULT hr;
if(!_InitCom)
{
char *pTemp = "服务器不能初始化COM环境";
OutputMessageToFile(pTemp);
SendErrorMessage(sockClient , pTemp);
return;
}
#ifdef _DEBUG
OutputMessageToFile("开始查询数据库");
#endif
if FAILED(hr = CoCreateInstance (CLSID_SQLDMOServer, NULL, CLSCTX_INPROC_SERVER,
IID_ISQLDMOServer, (LPVOID*)&pSQLServer))
{
char *pTemp = "不能初始化SQLDMOServer组件";
OutputMessageToFile(pTemp);
SendErrorMessage(sockClient , pTemp);
return;
}
if FAILED(hr = CoCreateInstance (CLSID_SQLDMOBackup, NULL, CLSCTX_INPROC_SERVER,
IID_ISQLDMOBackup, (LPVOID*)&pSQLBackup))
{
char *pTemp = "不能初始化SQLDMOBackup组件";
OutputMessageToFile(pTemp);
SendErrorMessage(sockClient , pTemp);
pSQLServer->Release();
return;
}
pSQLServer->SetLoginTimeout (30);
pSQLServer->SetLoginSecure (TRUE);
if(FAILED(pSQLServer->Connect()))
{
char *pTemp = "不能连接到SQL数据库";
OutputMessageToFile(pTemp);
SendErrorMessage(sockClient , pTemp);
pSQLBackup->Release();
pSQLServer->Release();
return;
}
// Get the database collection and the number of the databases.
pSQLServer->GetDatabases (&pDatabases);
pSQLServer->GetDatabaseCount (&lNumDB);
_bstr_t strDatabases("");
#ifdef _DEBUG
this->OutputMessageToFile("Put the non-system database names to the combo box");
#endif
// Put the non-system database names to the combo box.
for (lCount = 0; lCount < lNumDB; lCount++)
{
pDatabases->GetItemByOrd (lCount, &pDatabase);
pDatabase->GetName (&lpDBName);
pDatabase->GetSystemObject (&bSystemObj);
if (!bSystemObj)
{
strDatabases += "#";
strDatabases += lpDBName;
}
pDatabase->Release();
}
pDatabases->Release();
#ifdef _DEBUG
OutputMessageToFile(strDatabases);
#endif
//if(strDatabases.length() > 0)
{
struct Response *pResponse;
int len = sizeof(struct Response) + strDatabases.length() + 1;
PChar pBuff(new char[len]);
pResponse = (struct Response *)(char *)pBuff;
pResponse->sign = 0x7171;
pResponse->size = len;
pResponse->type = RT_SUCCEED;
strcpy(pBuff + sizeof(struct Response) , (char *)strDatabases);
sendn(sockClient , pBuff , len);
//strDatabases.ReleaseBuffer();
}
pSQLServer->DisConnect ();
pSQLBackup->Release();
pSQLServer->Release();
}
void CSQLBackupService::SendConnectSucceed(MySocket & sockClient)
{
struct Response _response;
_response.sign = 0x7171;
_response.type = RT_SUCCEED;
_response.size = sizeof(_response);
if(sendn(sockClient , (char *)&_response , sizeof(_response)) != sizeof(_response))
{
OutputMessageToFile("网络传输异常");
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?