用VC进行典型网络数据库系统软件设计

一、概述
  
  本系统为内部系统,帐户由管理员添加、管理;
  分为两个组,User组和Boss组。Boss组的帐户可以发广播通知;
  任意两个用户间可以互相通信;
  数据库接口用DAO,网络通信用 CSocket+CSocketFile;
  二、详细设计
  
  1、数据库设计
  
  本系统只是一个消息通信模型,这里的数据库设计比较简单。
  
  ER图:
  
   
   
  把ER模型转为关系模型,共两个表:
  
  User (No , Name ,Password ,G#) 候选键:No 外键:G#
  Group (G# , GroupName ,Demo ) 主键 :G#
  
  2、消息格式设计
  
  <1>、传送的消息共有5类------登录消息,验证返回消息,普通消息,用户列表消息,通知消息。定义一个枚举类型:
  
  enum MSGTYPE {LOGIN , LOGINResponse , CHATTING , USERList , NOTICE};
  <2>、定义消息类
  
  class CMsg : public CObject
  {
  public:
     int m_eType;  //枚举类型,记录消息类型
     CString m_strMsg;  //消息
     CMsg();
     virtual ~CMsg();
     void Serialize(CArchive &ar); //消息类系列化函数,发送和接受消息时用。
  };
  <3>、m_strMsg 为消息类中存放消息的成员,它的具体格式随着消息类型m_eType不同而不同。
   
  
  m_eType m_strMsg
  LOGIN 呢称|密码
  LOGINResponse GOOD|欢迎!(BOSS) 或 FAILED|验证失败!
  CHATTING 发给(来自)的用户名|消息内容
  USERList 呢称1|呢称2|…|呢称n|END
  NOTICE ALL|消息内容 或 来自的用户|消息内容
  
  m_strMsg中个内容用“|”隔开,用函数Decode(int n,CString strMsg) 获的相应的内容。
  
  
  CString Decode(int n,CString strMsg)
  {
       int pos;
       CString str;
       for(int i=1;i<=n;i++)
       {
         pos=strMsg.Find ("|",0);
         if(pos<0)
              str=strMsg;
           else
             str=strMsg.Left (pos);
  
         strMsg=strMsg.Right(strMsg.GetLength ()-pos-1);
       }
       return str;
  }
  <4>、消息发送接收的序列化函数
  void CMsg::Serialize (CArchive &ar)
  {
     if(ar.IsStoring())
     {
       ar<<m_strMsg<<m_eType;
     }
     else
     {
       ar>>m_strMsg>>m_eType;
     }
  }
  3、通信协议设计
  验证。客户端发送LOGIN消息,服务器回应 LOGINResponse消息;
  通信。客户端发送CHATTING 或 NOTICE 消息,服务器端根据接收到的消息,发送CHATTING,NOTICE或 USERList 消息。
  4、服务器设计
  
  <1>、建立工程
  
  ①、用MFC AppWizard(exe) 新建一个“单个文档”的工程;
  ②、在Step 2 of 6中,选 “查看数据库不使用文件支持”,点击“Data Source..”按钮,然后在弹出的对话框中选 “DAO”类型,再浏览选择数据库文件Data.mdb. 按确定,再在弹出的窗口选User表;
  ③、点击Next到Step 4 of 6,选“windows Sockets”。网络功能支持;
  ④、按“NEXT“,最后点击 “完成”;
  <2>、在CSuperServerView中添加下列成员: int m_iPort;//服务器端口
   CSocketListen * m_pSocket; //监听套接字。
   CSocketClient m_SocketClient[Max];  //跟客户端通信的套接字。
   CArchive * m_pArOut; //发送消息时的序列化文档对象指针。
   CArchive * m_pArIn;  //接收消息时的序列化化文档对象指针。
   CSocketFile * m_pSF;  //套接字文件对象指针。
   CMsg msg;//消息类对象
   CString Decode(int n,CString strMsg); //消息的解码函数
   void SendUserList();
   bool CheckLogin(CSocketClient *pClient);
   void MyReceive(CSocketClient *pClient);
   void MyClose(CSocketClient *pClient);
   void MyAccept();
  <3>、CSuperServerView类的关键成员函数:
  void CSuperServerView::MyReceive(CSocketClient *pClient)
  {
      m_pSF=new CSocketFile(pClient);
      m_pArIn=new CArchive(m_pSF,CArchive::load);
      msg.Serialize (*m_pArIn);
      int i;
      bool bOK=false;
  
      switch(msg.m_eType )
      {
     case LOGIN:     //处理用户登录。
     {
     m_pSF=new CSocketFile(pClient);
     m_pArOut=new CArchive(m_pSF,CArchive::store);
     msg.m_eType =LOGINResponse;
     if(CheckLogin(pClient))
     {
     if(!pClient->m_bBoss)
     {
     msg.m_strMsg="GOOD|欢迎!";
     bOK=true;
     }
     else
     {
     msg.m_strMsg="GOOD|BOSS";
     bOK=true;
     }
     else
     {
     msg.m_strMsg="FAILED|验证失败!";
     }
     msg.Serialize (*m_pArOut);
     m_pArOut->Flush ();
  
     if(bOK) SendUserList();
     break;
     }
     case CHATTING:  //处理普通消息
     {
    for(i=0;i<Max;i++)
        {
           if(m_SocketClient[i].m_bBusy)
      {
     if(m_SocketClient[i].m_strName ==Decode(1,msg.m_strMsg))
     {
     m_pSF=new CSocketFile(&m_SocketClient[i]);
     m_pArOut=new CArchive(m_pSF,CArchive::store);
     msg.m_strMsg=pClient->m_strName+"|"+Decode(2,msg.m_strMsg);
     msg.Serialize (*m_pArOut);
     m_pArOut->Flush ();
     break;
     }
       }
    }
    break;
        }
     case NOTICE:    //处理广播消息。
        {
     msg.m_strMsg=pClient->m_strName+"|"+Decode(2,msg.m_strMsg);
     for(i=0;i<Max;i++)
     {
     if(m_SocketClient[i].m_bBusy &&
    m_SocketClient[i].m_strName != pClient->m_strName)
     {
     m_pSF=new CSocketFile(&m_SocketClient[i]);
     m_pArOut=new CArchive(m_pSF,CArchive::store);
     msg.Serialize (*m_pArOut);
     m_pArOut->Flush ();
         }
       }
     break;
        }
      }
  }
  
  void CSuperServerView::MyAccept()
  {
   for(int i=0;i<Max;i++)
   {
   if(!m_SocketClient[i].m_bBusy)
   {
   m_pSocket->Accept (m_SocketClient[i]);
   m_SocketClient[i].GetView (this);
   break;
   }
   }
  }
  
  void CSuperServerView::OnStartServer()  //开始服务
  {
   m_pSocket=new CSocketListen(this);
   m_pSocket->Create (m_iPort,SOCK_STREAM);
   m_pSocket->Listen ();
   m_staState.SetWindowText("正在监听......");
  }
  
  void CSuperServerView::OnStopServer()  //关闭服务
  {
   if(m_pSocket) m_pSocket->Close ();
   for(int i=0;i<Max;i++)
   {
   if(m_SocketClient[i].m_bBusy)
   {
   m_SocketClient[i].Close();
   m_SocketClient[i].m_bBusy=false;
   }
   }
   m_staState.SetWindowText("服务关闭");
  }
  数据库维护操作函数: void CSuperServerView::OnButtonAdd() //添加帐户
  {
    CAddDlg dlg;
    if(dlg.DoModal()==IDOK)
    {
      if(dlg.m_strName!="")
      {
        m_pSet->AddNew ();
        m_pSet->m_Name=dlg.m_strName;
        m_pSet->m_Password=dlg.m_strPwd;
        m_pSet->m_G_=dlg.m_iG;
        m_pSet->Update ();
        UpdateData(FALSE);
      }
     }
  }
  
  void CSuperServerView::OnButtonDel()   //删除帐户
  {
    m_pSet->Delete ();
    m_pSet->MoveNext ();
    if(m_pSet->IsEOF ())
      m_pSet->MoveFirst();
  
    UpdateData(FALSE);
  }
  
  void CSuperServerView::OnButtonModify() //修改帐户信息
  {
     CAddDlg dlg;
     dlg.m_strName=m_pSet->m_Name;
     dlg.m_strPwd=m_pSet->m_Password;
     dlg.m_iG=m_pSet->m_G_;
     if(dlg.DoModal()==IDOK)
     {
      if(dlg.m_strName!="")
      {
         m_pSet->Edit ();
         m_pSet->m_Name=dlg.m_strName;
         m_pSet->m_Password=dlg.m_strPwd;
         m_pSet->m_G_=dlg.m_iG;
         m_pSet->Update ();
         UpdateData(FALSE);
      }
     }
  }
  
  void CSuperServerView::OnButtonFind() // 查找帐户
  {
    CFindDLG dlg;
    if(dlg.DoModal()==IDOK)
    {
      if(dlg.m_strKey!="")
      {
        CString m_strName;
        UpdateData(TRUE);
        m_strName=dlg.m_strKey ;
  
        if(m_pSet->IsOpen ())
          m_pSet->Close ();
  
        m_pSet->Open(AFX_DAO_USE_DEFAULT_TYPE,"SELECT * FROM user where Name=''"+m_strName+"''");
        UpdateData(FALSE);
      }
    }
  }
  
  CSocketListen类中的接受事件函数OnAccept(int nErrorCode)。
  
  void CSocketListen::OnAccept(int nErrorCode)
  {
     m_pView->MyAccept ();
     CSocket::OnAccept(nErrorCode);
  }
  
  CSocketClient类中的接收消息函数。
  
  void CSocketClient::OnClose(int nErrorCode)
  {
     // TODO: Add your specialized code here and/or call the base class
     m_pView->MyClose(this);
     CSocket::OnClose(nErrorCode);
  }
  
  CSocketClient类传递主窗口指针函数:
  
  void CSocketClient::GetView(CSuperServerView *pView)
  {
     m_pView=pView;
  }
  
  <4>、程序界面
  
   
  
  5、客户端设计。
  
  <1>、建立一个名为Client,基与对话框的应用程序,在Step 2 of 6中选Windows Sockts支持,
  <2>、在CClientDlg中添加成员。
      CString Decode(int n,CString strMsg);
      CMsg msg;
      CMySocket * m_pSocket;
      CArchive * m_pArOut;
      CArchive * m_pArIn;
      CSocketFile * m_pSF;
  
      void MyReceive();
  
  在CMySocket类中添加成员。    CClientDlg * m_pDlg;
      CMySocket(CClientDlg *pDlg);
  
  构造函数实现,获得指向主对话框的指针
  CMySocket::CMySocket(CClientDlg *pDlg)
  {
      m_pDlg=pDlg;
  }
  
  <3>、关键函数 BOOL CClientDlg::OnInitDialog()
  {
     ...
     m_strHost="192.168.1.126";
     m_iPort=1234;
     UpdateData(FALSE);
     GetDlgItem(IDC_BUTTON_SEND)->EnableWindow(false);
     Expand(0);
  
     return TRUE; // return TRUE unless you set the focus to a control
  }
  
  void CClientDlg::OnLogin() //登录函数
  {
     UpdateData(TRUE);
     GetDlgItem(IDC_BUTTON1)->SetWindowText("Wait");
     m_pSocket=new CMySocket(this);
     m_pSocket->Create();
     int nTry=3,n;
     do{
      n=m_pSocket->Connect (m_strHost,m_iPort);
     }while(n!=1 && nTry--);
    if(n==1)
    {
      Sleep(2000);
      m_pSF=new CSocketFile(m_pSocket);
      m_pArOut=new CArchive(m_pSF,CArchive::store);
      m_pArIn=new CArchive(m_pSF,CArchive::load);
      msg.m_eType =LOGIN;
      msg.m_strMsg =m_strName+"|"+m_strPwd;
      msg.Serialize (*m_pArOut);
      m_pArOut->Flush();
    }
    else
    {
      GetDlgItem(IDC_BUTTON1)->SetWindowText("Login");
      GetDlgItem(IDC_BUTTON1)->EnableWindow(true);
      AfxMessageBox("网络原因,没连上服务器!");
    }
  }
  
  void CClientDlg::MyReceive()  //接收消息函数
  {
    msg.Serialize (*m_pArIn);
    int i=0;
    CString str;
    switch(msg.m_eType )
    {
    case LOGINResponse:
      str=Decode(1,msg.m_strMsg);
      if(str=="FAILED")
      {
        str=Decode(2,msg.m_strMsg);
        m_pSocket->Close();
        AfxMessageBox(str);
      }
      else
      {
        Expand(true);
        GetDlgItem(IDC_BUTTON1)->SetWindowText("Login");
        GetDlgItem(IDC_BUTTON1)->EnableWindow(false);
        GetDlgItem(IDC_BUTTON_SEND)->EnableWindow(true);
      }
      break;
    case USERList:
      str=Decode(++i,msg.m_strMsg);
      m_ctrList.ResetContent();
      while(str!="END")
      {
        if(str!=m_strName)
          m_ctrList.AddString(str);
        str=Decode(++i,msg.m_strMsg);
      }
      UpdateData(FALSE);
      break;
    case CHATTING:
      MessageBox(Decode(2,msg.m_strMsg),"来自"+Decode(1,msg.m_strMsg)+"的消息:");
      break;
    case NOTICE:
      MessageBox(Decode(2,msg.m_strMsg),"来自"+Decode(1,msg.m_strMsg)+"的通知:");
      break;
    }
  }
  
  CMySocket类中的事件函数OnReceive(int nErrorCode)。 void CMySocket::OnReceive(int nErrorCode)
  {
   m_pDlg->MyReceive (); //调用主窗口的接收函数
   CSocket::OnReceive(nErrorCode);
  }
  
  <4>、程序界面
  
  ①、登录界面
  
   
  
  ②、登录成功(左为User组用户登录后界面,右为Boss组的)
  
   
  
  ③、发送消息
  
   
  
  ④、接收消息
  
  
  
  三、结束语
  
    这是一个基于网络和数据库的系统模型,有点学习的价值。程序还有一些功能没完善的地方,并且存在一些Bug。
  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值