• 基于C/S 结构的IM即时通讯软件上篇


     目的:实现类似QQ群聊的聊天室,可以看到好友列表及互相传送信息。

    分析:可基于C/S结构实现即时通讯

    1、创建基于对话框的MFC程序(支持windows套接字),并增加相应的类与结构体,完善对话框界面。

            服务器端:新增两个基于CSocket的类CClientSocket/CServerSocket分别用于服务与监听;并新增一个结构体信息,用于对客户端传输的信息(消息类型与长度)进行甄别。

        

            客户端:新增基于CSocket的类CClientSocket用于服务;并新增一个结构体信息,用于对客户端传输的信息(消息类型与长度)进行甄别。

    结构体信息,用于标识传输的内容类型

    1 typedef struct tagHeader
    2 {
    3     char type;
    4     int len;
    5 }Header, *pHeader;
    6 #define LOGIN_IO    1   //后面可以继续完善,比如视频/音频/文件
    7 #define SEND_MESSAGE 3
    8 ;

    2、完善框架结构

            服务器:在Clientsocket.h声明Dlg类,便于进行指针操作,并标识登录的用户昵称,创建CPtrList链队列数据结构。

     1 class CCase006Dlg;
     2 class CClientSocket : public CSocket
     3 {
     4 public:
     5     CString m_strName;        //请求登录的用户
     6     CPtrList *clist;        //储存队列的结构
     7     CCase006Dlg* m_dlgserver;    //对话框指针机制
     8     CClientSocket(CPtrList*list);    //生成一个socket队列
     9 
    10     CCase006Dlg* m_Dlg;
    11     void GetDlg(CCase011Dlg *dlg);
    12 }

             在Clientsocket.cpp中包含结构体头文件,并实现指针函数

    1 #include "tagHeader.h"
    2 
    3 // CClientSocket
    4 CClientSocket::CClientSocket(CPtrList *list) : m_dlgserver(NULL)
    5 {
    6     clist=list;
    7 }

           在CSeverSocket.h中定义列表对象-CPtrList connectList;

           在CSeverSocket.cpp中添加结构体头文件;

           在CXXXXDlg.h中声明套接字类,并定义指针对象与用户列表更新函数

     1 class CServerSocket;    //监听套接字类
     2 class CClientSocket;    //创建与客户端通信的套接字类
     3 
    // CCase006Dlg 对话框 4 class CCase006Dlg : public CDialog 5 { 6 // 构造 7 public: 8 CCase006Dlg(CWnd* pParent = NULL); // 标准构造函数 9 CString m_str_name; //用于标识管理员名 10 CClientSocket* clientsocket; //定义套接字指针 11 CServerSocket* m_serversocket; 12 void UpdateUser(CClientSocket* psocket); //声明用户更新函数

           在CXXXXDlg.cpp中包含头文件,并在初始化函数中初始化Socket指针对象

     1 #include "ServerSocket.h"
     2 #include "ClientSocket.h"
     3 #include "tagHeader.h"
     4 
     5 BOOL CCase006Dlg::OnInitDialog()
     6 {
     7     serversocket=NULL;
     8     clientsocket =NULL;
     9         ......
    10 }

            客户端:在 Clientsocket.h中定义登录用户名,并定义一个窗口指针及函数

    1 class CCase005Dlg;   //注意声明类
    2 class CClientSocket : public CSocket
    3 {
    4 public:
    5     CCase005Dlg *m_Dlg;
    6     CString m_str_name;        //登录用户
    7     void GetDlg(CCase005Dlg *dlg);
    8 };

            在ClientSocket.cpp中声明结构体,并实现窗口指针获取函数

    1 #include "Case005Dlg.h"
    2 #include "tagHeader.h"
    3 
    4 // CClientSocket 成员函数
    5 void CClientSocket::GetDlg(CCase005Dlg *dlg)
    6 {
    7     m_dlg=dlg;
    8 }

           在CXXXXDlg.h中声明套接字类,并定义指针对象与用户列表更新函数以及是否获取信息函数

     1 #include "ClientSocket.h"
     2 
     3 class CCase005Dlg : public CDialog
     4 {
     5 // 构造
     6 public:
     7     CClientSocket *m_clientsocket;
     8     void Updateuser();
     9     BOOL GetmsgFromRoom();
    10          ......
    11 }

            在CXXXXDlg.cpp中包含头文件,并在初始化函数中初始化Socket指针对象

    1 #include "ClientSocket.h"
    2 #include "tagHeader.h"

            此时已完成基本框架体系结构,接下来实现通信相关函数。

    3、实现界面事件函数

        服务器端:单击" 开始" 按钮开始监听

     1 void CCase011Dlg::OnBnClickedBnOpen()
     2 {
     3     // TODO: 在此添加控件通知处理程序代码
     4     UpdateData();
     5     serversocket=new CServerSocket;       //开启服务,定义一个服务对象
     6 
     7     BYTE nfield[4];
     8     CString strIP;
     9     UpdateData();    //需要更新
    10 
    11     //将IP传给地址框
    12     m_edit_ip.GetAddress(nfield[0],nfield[1],nfield[2],nfield[3]);
    13     strIP.Format("%d.%d.%d.%d",nfield[0],nfield[1],nfield[2],nfield[3]);
    14     CTime time=CTime::GetCurrentTime();
    15 
    16     if(m_str_name.IsEmpty())                    //对输入信息判定,,可简写
    17     {
    18         AfxMessageBox("请先登记管理员名!");
    19         return ;
    20     }
    21     if(m_edit_ip.IsBlank())
    22     {
    23         AfxMessageBox("请配置聊天室IP");
    24         return ;
    25     }
    26     if(m_str_port.IsEmpty())
    27     {
    28         AfxMessageBox("请配置要开放的端口");
    29         return ;
    30     }
    31     
    32     //开启聊天室,首先创建用于监听的套接字
    33     if(serversocket->Create(atoi(m_int_port),1,strIP))
    34     {
    35         m_editbox.SetWindowText("");
    36         m_editbox.ReplaceSel("聊天室开启成功!\r\n");     //此处使用的是编辑框控件,所以需使用replaceSel        
    CString temp=time.Format("%Y-%m-%d"); //增加时间排头 37 m_editbox.ReplaceSel("日期:"+temp+"\r\n"); //编辑框输出信息 38 temp=time.Format("%H:%M:%S"); 39 theApp.m_str_name=m_str_name; //如果想要实现聊天界面标题为登录者 40 m_editbox.ReplaceSel(temp+" 管理员"+theApp.m_str_name+"开放聊天室\r\n"); 41 } 42 if(serversocket->Listen()) //打开监听 43 { 44 m_editbox.ReplaceSel("等待成员加入。。。\r\n"); 45 } 46 //目前无人,因此仅有管理员一人在线 47 m_listbox.ResetContent(); 48 m_listbox.AddString(theApp.m_str_name+"(管理员)"); 49 this->SetWindowTextA("管理员:"+m_str_name+"服务器端"); 50 }

           更新用户列表处理函数

    void CCase011Dlg::UpdateUser(CClientSocket* psocket)
    {
        m_listbox.ResetContent();        //清空列表
        m_listbox.AddString(theApp.m_strName+"(管理员)");    //添加管理员用户
    
        CString userInfo;
        userInfo = theApp.m_str_ame+"(管理员)"+"&";    //添加管理员信息
        if(clientsocket!=NULL)
        {
            CClientSocket* psock=NULL;
            POSITION pos=clientsocket->clist->GetHeadPosition();    //获取列表头位置
            while(pos!=NULL)
            {
                psock=(CClientSocket*)clientsocket->clist->GetNext(pos);  
                m_listbox.AddString(psock->m_str_name);   
                userInfo+=(psock->m_strName+"&");        //逐个增加已经记录的用户名
            }
            Header head;
            head.type=LOGIN_IO;
            head.len=userInfo.GetLength();
            POSITION po=clientsocket->clist->GetHeadPosition();
            while(po!=NULL)            //将最新的用户列表转发给各个用户
            {
                psock=(CClientSocket*)clientsocket->clist->GetNext(po);
                psock->Send((char*)&head,sizeof(Header));
                psock->Send((LPCTSTR)userInfo,userInfo.GetLength());
            }
        }
    }
  • 相关阅读:
    乱七八杂
    转化跟踪设置说明
    Photoshop图象切片保存为网页HTML(DIV+CSS布局)的方法
    HTTP 错误 403.14
    打开asp出现An error occurred on the server when processing the URL
    ADODB.Connection 错误 '800a0e7a'
    修改客户端连接的服务器IP地址(内部使用)
    关于云计算的10个常见问题解答
    云安全的11个挑战及应对策略
    如何鉴别一个区块链项目的真假?
  • 原文地址:https://www.cnblogs.com/tobybain/p/10599982.html
Copyright © 2020-2023  润新知