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

本文介绍了如何实现局域网内的聊天系统客户端框架,主要涉及CClientDlg和CChatDlg两个关键组件的设计,通过这些组件实现用户交互和聊天功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

主要包含类:

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.youkuaiyun.com/detail/wudaijun/4911762


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值