局域网聊天系统__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



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值