局域网聊天系统__6.客户端框架实现

来源:互联网 发布:周杰被黑真相知乎 编辑:程序博客网 时间:2024/05/17 06:49
主要包含类:

CUserInfo 和 CChatPacket 和服务器定义的一致
CChatSocket用于和服务器或其他用户交互数据(类里面内置两个指针,分别指向CClientDlg和CChatDlg 以有效指针来辨别和谁通信)
     重写OnReceive和OnClose 均调用对应对话框函数处理
CListenSocket用于监听其他用户的连接请求 在OnAccept和OnClose中调用CClientDlg的函数处理
CLogInDlg用与用户输入登录信息

COffMsgDlg 用于显示离线消息 

 用户点击回复时 调用CClientDlg::CreateChatDlg 该函数根据用户状态创建不同的聊天对话框

CClientDlg和CChatDlg即为核心实现类
  • CClientDlg

          在登录成功后

        与服务器交互
/**     读取并且处理服务器发来的数据包*/void CClientDlg::ReadAndProcessPacket(){     CChatPacket packet;     //临时链表用于保存读取的用户链表信息     CObList obList;     packet.m_pUserlist = &obList;     packet.Serialize(*m_pArchiveIn);     switch(packet.m_type)     {          //收到服务器信息 显示然后退出     case CChatPacket::SERVERMSG:          MessageBox(packet.m_strMsg);          EndDialog(IDCANCEL);          break;                   //收到用户链表 更新保存的链表并显示     case CChatPacket::USERLIST:          //更新链表          UpdateUserList(obList);          //刷新显示          UpdateUserListCtrl();          //将自身状态从登录改为在线          m_userinfo.m_eStatue = CUserInfo::ONLINE;          break;          //收到转发的离线消息 显示     case CChatPacket::MESSAGE:          ShowOfflineMsg(packet);          break;     default:          break;              }}     与用户交互         1.用户双击请求聊天: /**     双击用户列表的某一用户时 触发*/void CClientDlg::OnDblclkListUser(NMHDR* pNMHDR, LRESULT* pResult){     // TODO: Add your control notification handler code here     NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;     if (pNMListView->iItem != -1)     {          int nSelected = pNMListView->iItem;          CString strPeerName = m_ctlUserList.GetItemText(nSelected, 0);          //如果不是和自己聊天          if(strPeerName != m_userinfo.m_strName)               CreateChatDlg(strPeerName);     }     *pResult = 0;}/**     负责根据用户状态的不同建立不同的聊天对话框*/void CClientDlg::CreateChatDlg(const CString &strPeerName){     //从用户链表中找到该用户     POSITION pos = NULL;     BOOL bFind = FALSE;     CUserInfo peeruserinfo;     for (pos=m_userlist.GetHeadPosition(); pos!=NULL;)     {          //找到该用户          peeruserinfo = *(CUserInfo*)m_userlist.GetNext(pos);          if (peeruserinfo.m_strName == strPeerName)          {               bFind = TRUE;               break;          }     }         if (bFind)     {          CChatDlg chatdlg(this, &m_userinfo, &peeruserinfo);          if (peeruserinfo.m_eStatue == CUserInfo::ONLINE)          {     //用户在线 则连接用户弹出对话框 并保存聊天记录               //设置在线聊天模式               chatdlg.SetChatMode(FALSE);               if(chatdlg.ConnectToPeer())               {                    chatdlg.DoModal();                    //保存聊天记录                    SaveChatRecord(&chatdlg);               }          }          else if (peeruserinfo.m_eStatue == CUserInfo::OFFLINE)          {     //如果发送的是离线消息 则由主窗口代为发送到服务器               //避免聊天窗口对服务器的再次连接               //设置离线聊天模式               chatdlg.SetChatMode(TRUE);               chatdlg.DoModal();                             //打包离线消息               CChatPacket packoffmsg;               packoffmsg.m_type = CChatPacket::MESSAGE;               packoffmsg.m_strMsg = chatdlg.GetChatRecord();               packoffmsg.m_userinfo = m_userinfo;               packoffmsg.m_peerUserinfo = peeruserinfo;               packoffmsg.m_sendtime = CTime::GetCurrentTime();               //发送数据包               SendPacket(packoffmsg);               //保存聊天记录               SaveChatRecord(&chatdlg);          }     }}

      2.用户被动聊天,即响应CListenSocket::OnAccept()
/**     当其他用户请求聊天时 调用此函数接受请求并创建聊天对话框*/BOOL CClientDlg::ProcessPendingAccept(){     //得到与一个聊天对话框相关联的一个CChatSocket     CChatDlg chatdlg(this);     chatdlg.InitChatSocket();     CChatSocket* pNewSocket = chatdlg.GetChatSocket();     //用该CChatSocket接收连接     SOCKADDR_IN addrPeer;     int len = sizeof(SOCKADDR_IN);     int ret = m_pListenSocket->Accept(*pNewSocket, (SOCKADDR*)&addrPeer, &len);             //找到请求连接的用户的信息     POSITION pos = NULL;     CUserInfo* pUserInfo = NULL;     BOOL bFind = FALSE;     for (pos = m_userlist.GetHeadPosition(); pos!=NULL;)     {          pUserInfo = (CUserInfo*)m_userlist.GetNext(pos);          if (pUserInfo->m_dwIP == addrPeer.sin_addr.S_un.S_addr                    && pUserInfo->m_eStatue == CUserInfo::ONLINE)          {               bFind = TRUE;               break;          }     }     //找到了则设置对话框对应的数据 显示聊天对话框     if (bFind)     {          chatdlg.SetUserInfo(&m_userinfo);          chatdlg.SetAimUserInfo(pUserInfo);          chatdlg.InitArchive();          chatdlg.SetChatMode(FALSE);          chatdlg.DoModal();          SaveChatRecord(&chatdlg);     }     return TRUE;}

//其他主要函数      void ProcessServerClose();                              //处理服务器退出或断开连接     BOOL ProcessPendingAccept();                         //处理新的用户聊天请求     void SaveChatRecord(CChatDlg* pChatDlg);          //保存聊天记录     void CreateChatDlg(const CString& strPeerName);     //根据用户状态创建聊天对话框     void ShowOfflineMsg(const CChatPacket& packet); //显示离线消息     void UpdateUserListCtrl();                              //更新用户列表显示     void UpdateUserList(CObList& oblist);               //收到服务器的用户列表时 更新     void ReadAndProcessPacket();                         //读取并处理服务器发来的数据包     void ProcessPendingRead();                              //调用ReadAndProcessPacket处理数据     BOOL BeginListen();                                        //创建并开启监听套接字     void SendPacket(CChatPacket& packet);               //向服务器发送数据包                                  BOOL ConnectToServer();                                   //连接到服务器     void InitListCtrlSetting();                              //初始化用户列表控件设置     BOOL Init();                                             //客户端初始化//主要数据成员     CObList m_userlist;                    //用户列表     SOCKADDR_IN m_addrHost;               //主机地址(端口为监听套接字端口)     CArchive* m_pArchiveOut;          //用于向服务器发送数据的文档对象     CUserInfo m_userinfo;               //本用户的信息     CArchive* m_pArchiveIn;               //用于接收服务器发送的数据的文档对象                   CSocketFile* m_pSocketFile;          //与服务器通信用的CSocketFile     CChatSocket* m_pChatSocket;          //与服务器聊天的CChatSocket     CImageList* m_pImageList;          //用户头像     CListenSocket* m_pListenSocket; //监听套接字



  • CChatDlg:
     该对话框用于在线聊天或者离线留言 通过一个bool变量m_bOfflineChat标识
     CChatDlg有两种初始化方式,默认构造和直接构造CChatDlg(CWnd* pParent, CUserInfo* puser, CUserInfo* paimuser)
     前者用于被动聊天 因为需要先构造CChatDlg用其成员变量m_pChatSocket来作为参数接收连接请求 之后才能得到对方用户信息,可通过SetPeerUserInfo来设置
     后者用于主动聊天,此时对方用户信息可以在CClientDlg中得到,因此直接构造。
     当聊天为在线聊天时,还需要调用InitArchive获得CSocket序列化支持


     CChatDlg主要函数和数据:
 // CChatDlg主要函数:     public:     void ProcessPeerClose();                              //当对方关闭聊天对话框时调用     CChatSocket* GetChatSocket();                         //得到聊天套接字     void InitChatSocket();                                   //创建聊天套接字     void SetAimUserInfo(const CUserInfo* puserinfo);//保存对方信息     void SetUserInfo(const CUserInfo* puserinfo);     //保存本用户信息     void InitArchive();                                        //初始化必需的CSocketFile和CArchive对象     void SendPacket(CChatPacket* pPacket);               //向对方发送数据包     void DisplaySentMsg(CString strInput);               //在聊天记录框中显示自己发送的信息     void DisplayRecvMsg(const CChatPacket& recvpacket);//在聊天记录框中显示接收的信息     ~CChatDlg();     void ProcessPendingRead();                              //当聊天套接字可读时,通过该函数处理     CString GetChatRecord();                              //得到聊天记录     void SetChatMode(BOOL bOfflineChat);               //设置聊天模式(True:离线留言 False 在线聊天)     bool ConnectToPeer();                                   //连接到对方         CChatDlg(CWnd* pParent, CUserInfo* puser, CUserInfo* paimuser);//主动聊天的构造函数   //  主要数据成员     CString m_strChatRecord;     //聊天记录     CArchive* m_pArchiveOut;     //发送数据的文档对象     CArchive* m_pArchiveIn;          //接收数据的文档对象     CSocketFile* m_pSocketFile;     //聊天套接字关联的CSocketFIle文件     CChatSocket* m_pChatSocket;     //聊天套接字     CUserInfo m_aimuserinfo;     //聊天对方的信息     CUserInfo m_userinfo;          //本用户的信息     BOOL m_bOfflineChat;          //标识聊天类型


主要函数实现
//发送数据:  /**     用户点击发送按钮 发送信息 并且更新聊天对话框显示*/void CChatDlg::OnBtnSend(){     // TODO: Add your control notification handler code here     //得到输入内容     CString strUserInput;     m_ctrlInput.GetWindowText(strUserInput);     //为空则不发送     if (strUserInput == "")          return;     if(m_bOfflineChat)          //离线留言 只需要负责界面显示 由主对话框负责发送给服务器     {          //清空输入框          m_ctrlInput.SetWindowText("");                   //更新聊天框显示          DisplaySentMsg(strUserInput);     }     else     //在线聊天     {          //打包数据          CChatPacket msgpacket;          msgpacket.m_type = CChatPacket::MESSAGE;          msgpacket.m_userinfo = m_userinfo;          msgpacket.m_peerUserinfo = m_aimuserinfo;          msgpacket.m_strMsg = strUserInput;          msgpacket.m_sendtime = CTime::GetCurrentTime();                   //发送数据          SendPacket(&msgpacket);          //清空输入框          m_ctrlInput.SetWindowText("");          //更新聊天框显示          DisplaySentMsg(strUserInput);     }}//接收数据 由CChatSocket::OnReceive调用void CChatDlg::ProcessPendingRead(){     do     {          CChatPacket packet;          packet.Serialize(*m_pArchiveIn);          if (packet.m_type == CChatPacket::MESSAGE)          {               DisplayRecvMsg(packet);          }     }while(!m_pArchiveIn->IsBufferEmpty());}

完整源代码下载地址点击这里http://download.csdn.net/detail/wudaijun/4911762


原创粉丝点击