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 + -
显示快捷键?