局域網聊天系統__3.服務器框架實現

CUserInfo類 主要包含一些必要數據以及Serialize支持
class CUserInfo : public CObject
{
public:
     DECLARE_SERIAL(CUserInfo);
     CUserInfo();
     virtual ~CUserInfo();
     CUserInfo(const CUserInfo& userInfo);
    
     enum USERSTATUE
     {
          ONLINE,          //在線
          OFFLINE,         //離線
          LOGIN,           //登錄
          UNKNOWN          //未知
     };
public:
     void Init();
     virtual void Serialize(CArchive& ar);
     CUserInfo &operator = (const CUserInfo &userInfo);
public:
     CString          m_strName;          //暱稱
     CString          m_strPassword;     //密碼
     USERSTATUE     m_eStatus;          //狀態
     DWORD          m_dwIP;               //地址
     USHORT          m_nPort;          //端口
     CTime          m_time;               //時間
};

通信數據包類CChatPacket

 class CChatPacket : public CObject
{
public:
     DECLARE_SERIAL(CChatPacket);
     CChatPacket();
     virtual ~CChatPacket();
     enum PACKETTYPE
     {
          MESSAGE,     //用戶發送給服務器保存的離線消息
          USERLIST,     //服務器發送給用戶的用戶列表
          SERVERMSG,     //服務器發送給用戶的普通消息
          UNKNOWN          //未知
     };
public:
     virtual void Serialize(CArchive& ar);
     void Init();     //實現一些必要的數據的初始化
public:
     //包成員變量 括號裏說明某些變量的單邊可見性
     CUserInfo     m_userInfo;               //發送該包的用戶信息(User->Server)
     PACKETTYPE     m_type;                    //包類型              
     CString          m_strMsg;               //消息                   
     CObList*     m_pUserList;          //用戶列表               (Server->User)
     CUserInfo     m_offlineUserInfo;     //離線用戶信息          (User->Server)
     CTime          m_sendTime;               //發送時間              
    
};

監聽套接字CListenSocket類

     該類派生自CSocket,用於監聽客戶端連接請求,並且交由服務器主界面類處理(因爲主界面類維護並處理整個客戶端鏈表)。並且服務器界面類創建並監聽
     CListenSocket在整個服務器中是唯一的,在服務器創建後它僅重載OnAccept函數,該函數中唯一做的事情就是調用服務器界面線程(CServerDlg)對應函數來完成處理,因此自然CListenSocket在構造時需要傳入一個CServerDlg的指針,並且保存,以便調用CServerDlg對應函數
   CListenSocket::CListenSocket(CServerDlg* pServer)
     {
          m_pServerDlg = pServer;
     }
     void CListenSocket::OnAccept(int nErrorCode)
     {
m_pServerDlg->ProcessPendingAccept();
      }
客戶端套接字類CClientSocket
該類也派生自CSocket,負責和客戶端進行簡單的數據傳輸,並且接受客戶端數據可讀通知。它重載了CSocket的虛函數OnClose OnReceive  當有可讀數據時,OnReceive觸發,OnReceive中將接受數據的操作交由CServerDlg類進行處理,當有客戶端連接斷開時,OnClose觸發,此時調用CServerDlg的相應函數將該用戶移出在線列表
     另外,該類還包含一些對該客戶端的用戶信息的保存和讀取的操作,並且可以向客戶端發送數據,用以服務器主類CServerDlg調用。

     CClientSocket::CClientSocket(CServerDlg* pServer)
      {
          m_pServer = pServer;
        m_pSocketFile = NULL;
      }
void CClientSocket::Init()
{
     m_pSocketFile = new CSocketFile(this);
}
     void CClientSocket::OnReceive(int nErrorCode)
     {
     //創建文檔對象  以便服務器從此讀取數據包
     CArchive* pArchiveIn = new CArchive(m_pSocketFile, CArchive::load);
    
     //如果服務器處理未通過  則刪除自身
     int ret = m_pServer->ProcessPendingReceive(this, pArchiveIn);
     delete pArchiveIn;

     if (!ret)
     {
          delete this;
     }
      }
void CClientSocket::OnClose(int nErrorCode)
{
     //停止發送
     ShutDown(1);
     //移除在線列表
     m_pServer->RemoveChatter(this);
     //刪除自身
     delete this;
}
void CClientSocket::SendUserMsg(CChatPacket &chatpacket)
{
     CArchive* pArchiveOut = new CArchive(m_pSocketFile, CArchive::store);

     //發送消息
     chatpacket.Serialize(*pArchiveOut);
     pArchiveOut->Flush();

     delete pArchiveOut;
     pArchiveOut = NULL;
}

void CClientSocket::SendUserList(CChatPacket* pUserListPacket)
{
     CArchive* pArchiveOut = new CArchive(m_pSocketFile, CArchive::store);
    
     pUserListPacket->Serialize(*pArchiveOut);
    
     pArchiveOut->Flush();
     delete pArchiveOut;
     pArchiveOut = NULL;
}
CClientSocket::~CClientSocket()
{
     if (m_pSocketFile)
          delete m_pSocketFile;    
}
 
接下來就是服務器的主類CServerDlg
服務器幾乎所有的操作和處理都在該類完成。
     主要實現:
          開啓服務器:
               創建並開啓監聽套接字
          從文件加載數據:
               加載用戶信息列表以及離線消息列表
          初始化服務器界面:
               根據用戶信息初始化服務器用戶信息列表
          當有新的連接請求時(由CListenSocket調用):
               創建客戶端套接字類,接受請求
          當有可讀數據(由CClienetSocket調用):
               讀入數據包,根據數據包類型進行相應處理
               如果是離線消息 替用戶保存
               如果是請求用戶列表,則: 
                    1.驗證該用戶的合法性
                    2.如果驗證通過 將該用戶加入到在線用戶列表(如果該用戶是新用戶,還需要更新用戶信息列表)
                    3.向所有在線用戶發送新的用戶列表(遍歷m_ChatterList,依次調用CClientSocket的SendUserList)
                    4.檢查離線消息列表,查看有無該用戶的離線消息,並且轉發
                    5.更新服務器界面
          當有消息向用戶發送:
               調用CClientSocket響應函數發送數據包
          當用戶在用戶列表項上單擊右鍵:
               彈出移除用戶菜單 將用戶移除列表 更新服務器顯示
          當有用戶下線時(CClientSocket調用)
               將該用戶移除在線用戶列表 更新服務器顯示
          當服務器退出時
               保存m_UserList m_OfflineMsgList數據到文件
               釋放m_ChatterList m_UserList m_OfflineMsgList
               釋放監聽套接字以及其他資源
#include "ClientSocket.h"
#include "UserInfo.h"
class CListenSocket;
class CClientSocket;
class CUserInfo;

class CServerDlg : public CDialog
{
// Construction
public:
     void DeleteAllChatters();     //釋放在線用戶列表
     void SaveUserList();          //保存用戶信息到文件並且釋放用戶信息鏈表
     void SaveOfflineMsg();          //保存離線消息到文件並且釋放離線消息鏈表
     void RemoveChatter(CClientSocket* pClient);//將pClient用戶從在線用戶列表中移除
     void SendUserListToAllChatter();//向所有在線用戶發送用戶列表
     BOOL ProcessPendingReceive(CClientSocket* pClient, CArchive* pArchiveIn);//接收並處理數據包
     void ProcessPendingAccept();//處理用戶連接請求
     void LoadOfflineMsg(CObList& obList);//從文件加載離線消息鏈表
     void LoadUserList(CObList& obList);  //從文件加載用戶信息鏈表
     void InitUserList();                    //將用戶信息鏈表填充到服務器界面
     void InitListCtrl();                    //初始化設置用戶信息列表控件
     BOOL StartService();                    //創建監聽套接字開啓監聽
     BOOL InitServer();                         //初始化服務器界面
     CServerDlg(CWnd* pParent = NULL);     // standard constructor
     ~CServerDlg();

// Dialog Data
     //{{AFX_DATA(CServerDlg)
     enum { IDD = IDD_SERVER_DIALOG };
     CListCtrl     m_ctlUserList;
     //}}AFX_DATA

     // ClassWizard generated virtual function overrides
     //{{AFX_VIRTUAL(CServerDlg)
     protected:
     virtual void DoDataExchange(CDataExchange* pDX);     // DDX/DDV support
     //}}AFX_VIRTUAL

protected:
          void UpdateServerListCtrl();                    //更新服務器顯示
          void TransmitMsg(CClientSocket* pClient);     //轉發離線消息
          void DeleteTempUserList(CObList& obList);     //刪除臨時列表
          void CopyUserList(CObList& obList);               //複製用戶列表(避開復制密碼)
          //驗證用戶合法性 並在必要時(用戶是新用戶),更新m_UserList
          BOOL VerifyUserAndUpdateUserList(CUserInfo& userInfo, CClientSocket* pClient);
// Implementation
protected:
     HICON m_hIcon;

     // Generated message map functions
     //{{AFX_MSG(CServerDlg)
     virtual BOOL OnInitDialog();
     afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
     afx_msg void OnPaint();
     afx_msg HCURSOR OnQueryDragIcon();
     afx_msg void OnDestroy();
     afx_msg void OnRclickUserList(NMHDR* pNMHDR, LRESULT* pResult);
     afx_msg void OnMenuDeleteUser();
     //}}AFX_MSG
     DECLARE_MESSAGE_MAP()
private:
              
     CObList m_OfflineMsgList;                    //離線消息鏈表 保存CChatPacket類型                   
     CObList m_ChatterList;                         //在線用戶列表 保存CClientSocket類型
     CObList m_UserList;                              //用戶信息列表 保存CUserInfo類型
     CImageList* m_pImageList;                    //用戶頭像圖片
     CListenSocket* m_pListenSocket;               //監聽套接字
};
具體實現參見源代碼
完整源代碼下載地址點擊這裏http://download.csdn.net/detail/wudaijun/4911762



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章