Chinaunix首页 | 论坛 | 博客
  • 博客访问: 9547101
  • 博文数量: 1227
  • 博客积分: 10026
  • 博客等级: 上将
  • 技术积分: 20273
  • 用 户 组: 普通用户
  • 注册时间: 2008-01-16 12:40
文章分类

全部博文(1227)

文章存档

2010年(1)

2008年(1226)

我的朋友

分类: 数据库开发技术

2008-03-14 13:34:13

下载本文示例代码

功能简述

  服务端(发送方)和客户端(接收方)定好数据库结构及内容格式后,由服务端将数据库生成指定XML格式文件后, 通过Socket发给客户端。客户端接收成功后,用收到的XML库格式文件,生成数据库。

用例图:

设计

  根据以上需求,采用VC6.0生成两个工程文件:DBClent(客户端及接收方)和DBServer(服务端及发送方)。其中DBClient负责接收XML库格式文件并生成数据库,DBServer负责生成指定格式的XML库文件与发送此文件给DBClient。

总体类图:

实现

1、数据库转换为XML格式设计规定:数据库用Database,在其节点属性中用name来指定数据库名称。其子节点可能有多个表,表节点名为:Table,其节点属性中name用来指定表名称。表节点下包括表结构描述Struct和内容描述Content。表结构中列名用节点Field表示,名称/类型/长度等在其属性中表示。表内容中用节点Record表示每个记录,详细信息在属性中表示。

示例: DBTest.xml



 
   
   
  
   
   
   
   
   
   
   
   
  
2、服务端(发送方)实现 采用Socket套接字在指定端口发送生成的XML库格式文件。生成程序界面效果如下:

示例代码如下:

// 发送指定的XML文件
#define PRE_AGREED_PORT 8686  // 端口号
#define SEND_BUFFER_SIZE 4096  // 缓冲区大小

BOOL CDBServerDlg::SendFileToRemoteRecipient(CString fName)
{

 AfxSocketInit( NULL );    
 CSocket sockSrvr; 
 sockSrvr.Create( PRE_AGREED_PORT ); // 指定端口创建socket
 sockSrvr.Listen();    // 侦听端口上的客户端
 CSocket sockConnection;
 sockSrvr.Accept( sockConnection );  // 用另一个socket接收连接
 
 // 是否成功
 BOOL bRet = TRUE;    

 int fileLength, cbLeftToSend;   // 文件长度及发送进度
 
 BYTE* sendData = NULL;   // 发送数据缓冲指针
 
 CFile sourceFile;
 CFileException fe;
 BOOL bFileIsOpen = FALSE;
 
 if( !( bFileIsOpen = sourceFile.Open( fName, CFile::modeRead | CFile::typeBinary, &fe ) ) )
 {
  TCHAR strCause[256];
  fe.GetErrorMessage( strCause, 255 );
  TRACE( "SendFileToRemoteRecipient encountered an error while opening the local file\n"
   "\tFile name = %s\n\tCause = %s\n\tm_cause = %d\n\tm_IOsError = %d\n",
   fe.m_strFileName, strCause, fe.m_cause, fe.m_lOsError );
  
  bRet = FALSE;
  goto PreReturnCleanup;
 }
 

 // 首先,发送文件长度
 fileLength = sourceFile.GetLength();
 fileLength = htonl( fileLength );
 
 cbLeftToSend = sizeof( fileLength );
 
 do
 {
  int cbBytesSent;
  BYTE* bp = (BYTE*)(&fileLength) + sizeof(fileLength) - cbLeftToSend;
  cbBytesSent = sockConnection.Send( bp, cbLeftToSend );
  
  // 是否出错
  if( cbBytesSent == SOCKET_ERROR )
  {
   int iErr = ::GetLastError();
   TRACE( "SendFileToRemoteRecipient returned a socket error while sending file length\n"
    "\tNumber of Bytes sent = %d\n"
    "\tGetLastError = %d\n", cbBytesSent, iErr );

   bRet = FALSE;
   goto PreReturnCleanup;
  }
  
  // 发送成功后, 剩余发送总数= 总长度-已发送长度
  cbLeftToSend -= cbBytesSent;
 }
 while( cbLeftToSend > 0 );
 
 
 // 然后,发送文件数据
 sendData = new BYTE[SEND_BUFFER_SIZE]; 
 
 cbLeftToSend = sourceFile.GetLength();
 
 do
 {
  // 从文件中读取指定缓冲字节
  int sendThisTime, doneSoFar, buffOffset;
  
  sendThisTime = sourceFile.Read( sendData, SEND_BUFFER_SIZE );
  buffOffset = 0;
  
  do
  {
   doneSoFar = sockConnection.Send( sendData + buffOffset, sendThisTime ); 
   
   // 是否出错
   if( doneSoFar == SOCKET_ERROR )
   {
    int iErr = ::GetLastError();
    TRACE( "SendFileToRemoteRecipient returned a socket error while sending chunked file data\n"
     "\tNumber of Bytes sent = %d\n"
     "\tGetLastError = %d\n", doneSoFar, iErr );
    
    bRet = FALSE;
    goto PreReturnCleanup;
   }
   
   // 发送成功后, 剩余发送字节及偏移
   buffOffset += doneSoFar;
   sendThisTime -= doneSoFar;
   cbLeftToSend -= doneSoFar;
  }
  while ( sendThisTime > 0 );
  
 }
 while( cbLeftToSend > 0 );
 
 
PreReturnCleanup:  // 结束及清理
 
 // 释放内存及关闭打开句柄
 delete[] sendData;
 
 if( bFileIsOpen )
  sourceFile.Close(); 
 
 sockConnection.Close();
 
 return bRet;
 
}
3、客户端(接收方)实现 接收XML库格式文件,并生成数据库。程序界面效果如下:

示例代码如下:

// 接收指定的XML文件
#define PRE_AGREED_PORT 8686  // 指定端口号
#define RECV_BUFFER_SIZE 4096  // 缓冲区大小

BOOL CDBClientDlg::GetFileFromRemoteSender(CString strIP, CString fName)
{
 // 创建客户端socket
 AfxSocketInit( NULL ); // 初始化socket
 CSocket sockClient;
 sockClient.Create();
 
 // 连接到指定IP和端口号
 sockClient.Connect( strIP, PRE_AGREED_PORT ); // PRE_AGREED_PORT 端口号被指定为 8686
 
 
 // 传送是否成功
 BOOL bRet = TRUE;        
 
 int dataLength, cbBytesRet, cbLeftToReceive; // 接收数据长度及进度
 
 BYTE* recdData = NULL;       // 接收数据缓冲
 
 CFile destFile;
 CFileException fe;
 BOOL bFileIsOpen = FALSE;
 
 // 打开或创建指定文件,用来接收数据
 if( !( bFileIsOpen = destFile.Open( fName, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary, &fe ) ) )
 {
  TCHAR strCause[256];
  fe.GetErrorMessage( strCause, 255 );
  TRACE( "GetFileFromRemoteSender encountered an error while opening the local file\n"
   "\tFile name = %s\n\tCause = %s\n\tm_cause = %d\n\tm_IOsError = %d\n",
   fe.m_strFileName, strCause, fe.m_cause, fe.m_lOsError );
  
  
  bRet = FALSE;
  goto PreReturnCleanup;
 }
 
 // 首先,获取文件长度
 cbLeftToReceive = sizeof( dataLength );
 do
 {
  BYTE* bp = (BYTE*)(&dataLength) + sizeof(dataLength) - cbLeftToReceive;
  cbBytesRet = sockClient.Receive( bp, cbLeftToReceive );
  
  // 是否出错
  if( cbBytesRet == SOCKET_ERROR || cbBytesRet == 0 )
  {
   int iErr = ::GetLastError();
   TRACE( "GetFileFromRemoteSite returned a socket error while getting file length\n"
    "\tNumber of Bytes received (zero means connection was closed) = %d\n"
    "\tGetLastError = %d\n", cbBytesRet, iErr );
   
   bRet = FALSE;
   goto PreReturnCleanup;
  }
  
  // 接收成功,剩余长度
  cbLeftToReceive -= cbBytesRet;
  
 }
 while( cbLeftToReceive > 0 );
 
 dataLength = ntohl( dataLength );
 
 // 然后,每次接收指定缓冲的数据
 recdData  = new byte[RECV_BUFFER_SIZE];
 cbLeftToReceive = dataLength;
 
 do
 { 
  int iiGet, iiRecd;
  
  iiGet = (cbLeftToReceive 0 );
 
PreReturnCleanup:  // 结束及清理
 
 // 释放内存及关闭打开句柄
 delete[] recdData;  
 
 if ( bFileIsOpen )
  destFile.Close();
 
 sockClient.Close();
 
 return bRet;
}

// 解析XML库并生成数据库
bool CBulidDB::Parse_XML_Document()
{
 if( !m_bDone )
 {
  if( Is_Tag( "" ) )
  {
   // 获取生成数据库名称
   if( Is_Having_Attribute( "name" ) )
    m_strDBName = Get_Attribute_Value();
  }
  
  if( Is_Tag( "" ) )
  {  
   // 获取库内表名
   if( Is_Having_Attribute( "name" ) )
    m_strTableName = Get_Attribute_Value();
  }
  
  // 库名或表名为空退出
  if( "" == m_strDBName || "" == m_strTableName )
   return false;
  
  // 获取主程序所在路径,存在sPath中
  CString sPath;
  GetModuleFileName( NULL, sPath.GetBufferSetLength( MAX_PATH + 1 ), MAX_PATH );
  sPath.ReleaseBuffer();
  int nPos;
  nPos = sPath.ReverseFind( ''\\'' );
  sPath = sPath.Left( nPos );
  
  CString lpszFile = sPath + "\\" + m_strDBName;
  CFileFind  fFind;
  BOOL bSuccess;
  bSuccess = fFind.FindFile( lpszFile );
  fFind.Close ();
  
  CDaoDatabase db;     // 数据库
  CDaoRecordset RecSet( &db );  // 记录集
  // 是否已有创建好的库文件,没有则创建它
  if( !bSuccess )
  {
   // 创建Mdb库
   db.Create( lpszFile );
   
   // 移动节点到指定位置
   Go_to_Parent("Table"); 
   Go_to_Child("Struct"); 
   Go_to_Child( "Field" );
   // 获取库结构
   CString sqlCmd = "CREATE TABLE " + m_strTableName + "(";
   while( Is_Tag( "" ) && Is_Child_of( "
" ) ) { CString strField = ""; // 列名 if( Is_Having_Attribute( "fieldName" ) ) strField = Get_Attribute_Value(); sqlCmd += strField + " "; // 列类型 if( Is_Having_Attribute( "fieldType" ) ) strField = Get_Attribute_Value(); sqlCmd += strField + "("; // 列长度 if( Is_Having_Attribute( "fieldLength" ) ) strField = Get_Attribute_Value(); sqlCmd += strField + "),"; // 同一级下一节点 if( !Go_Forward() ) break; } // 删除尾部多余逗号 if( -1 != sqlCmd.ReverseFind( '','' ) ) sqlCmd.Delete( sqlCmd.GetLength() - 1, 1 ); sqlCmd += ");"; // 创建库结构 db.Execute( sqlCmd ); CString strQuery = "SELECT * FROM " + m_strTableName; // 打开已创建的数据表 RecSet.Open( AFX_DAO_USE_DEFAULT_TYPE, strQuery, 0 ); // 移动节点到指定位置 Go_to_Parent("Table"); Go_to_Child("Content"); Go_to_Child( "Record" ); // 创建库内容记录 while( Is_Tag( "" ) && Is_Child_of( "
" ) ) { CString sqlRecordCmd = "INSERT INTO " + m_strTableName + "(Name,Age) VALUES("; CString strRecord = ""; // 名字 if( Is_Having_Attribute( "name" ) ) strRecord = Get_Attribute_Value(); sqlRecordCmd += "''" + strRecord + "'', "; // 年龄 if( Is_Having_Attribute( "age" ) ) strRecord = Get_Attribute_Value(); sqlRecordCmd += strRecord + ")"; // 插入记录 db.Execute( sqlRecordCmd ); // 同一级下一节点 if( !Go_Forward() ) break; } // 关闭记录集及库 RecSet.Close(); db.Close(); // 完成 m_bDone = true; AfxMessageBox( lpszFile + "Access库成功创建!" ); return true; } else { AfxMessageBox( lpszFile + "Access库已经存在!" ); } } return false; } 小结

  数据库远程备份基本功能已实现,还有很多待完善的地方,如服务端没有实现直接读取数据库生成指定XML库文件的功能。服务端和客户端没有实现多线程发送/接收等。

下载本文示例代码
阅读(1359) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~