用C++/MFC实现P2P和群聊功能的聊天小软件

final edit 2015-01-03

· 实现平台:
Window 8.1,Visual Studio 2013
Window 7, Visual Studio 2010

· 所用框架:
是基于Microsoft MFC框架的编程,以及基于html,css和javascript的web编程。

· 编程语言:
C++,java

· 软件介绍(Introduction):
MINET是一款能够进行群聊和P2P私聊的软件。我们通过一个服务器进行中介传输,使客户端之间可以进行通信。

· 功能简介:
 P2P聊天功能
 群聊功能(聊天室)
 同一网段(WIFI/校园网)之间通信
 匿名聊天功能
 修改用户个性签名功能
 后台数据库储存用户昵称,个性签名,在线状态
 在线用户列表,离线用户列表

· 工程设计(Project Design):

概要:
 协议:本软件的聊天功能基于UDP,经过测试,socket会出现不稳定情况。
 服务器:每个客户端与服务器之间都用一个socket连接。服务器的功能包括数据库读写,P2P之间的消息转发,群聊时消息的广播,在线/离线用户列表的更新广播
 客户端:客户端的功能主要包括发送聊天内容,发送个性签名更新,以及对从服务器中收到的消息进行分类处理。客户端根据从服务器接收的消息的type

过程:
每个客户端连接服务器用了一个socket,代码是写在MINET.cpp里面,也就是MAIN函数中,当我们的对话框发送消息时首先发给对话框所对应的客户端,然后由客户端的socket发送给服务器,那么服务器接收到消息之后,要转发消息,也是先发送个每个客户端,然后客户端再把消息怎么处理显示在对应的对话框中,我们的聊天都是使用服务器作为转发,就算是P2P的聊天也是利用服务器进行转发,群聊和私聊的不同就是转发的对象不通,怎么转发,下面介绍服务器的socket的实现会具体指出。

报文头的定义以及报文发送的格式:
Head.h:
用C++/MFC实现P2P和群聊功能的聊天小软件_第1张图片

其中,我们的header中的type定义了4中类型,登陆,发送消息,退出,更新在线用户列表。

我们socket中的消息通过两条发送,第一个是消息的类型,及即将要发送的第二条消息的长度,第二条消息即为发送的内容。第二条消息定义的格式如下,3#A#B#C#msg,可以解读为,3为当前聊天的人数,A为发消息的客户端(sender)而后面的两个B,C即为接收消息的两人(receiver),真正在对话框里显示的是msg,所以我们添加的匿名的额外功能可以直接改变msg的值,那么就会变得十分简单了。

服务器:

发送消息的方法:
    1.构建head。
        const int MSG_LOGOIN = 0x01; //登录
        const int MSG_SEND = 0x11;   //发送消息
        const int MSG_CLOSE = 0x02;  //退出
        const int MSG_UPDATE = 0x21; //更新信息

        typedef struct tagHeader{
            int type ;//协议类型
            int nContentLen; //将要发送内容的长度
            }HEADER ,*LPHEADER;

    2.一个报文的结构如下:

    -------------------------------------------------
    |   HEADER   |            content(报文内容)     |   
    -------------------------------------------------

· 发送消息时,先发送第一个socket出去,发送的是header(其中包含struct的type和nContentLen)。说明socket的类型type是“登录”,“发送消息”,“退出”或者“更新信息”,nContentLen说明了报文内容的content的长度。
· 发送第二个socket时,把真正的报文内容发送出去。
· 对于第二个socket的报文内容,我们定义的格式如下:
用“#”隔开用户的名字
(发送者和全部接收者先按姓名排好序,然后放入msg中)


|count # sender_name # receiver_name1 # receiver_name2 # receiver_name3 # message|


(count 是发送者以及全部接收者的人数)

· 项目整个头文件:
用C++/MFC实现P2P和群聊功能的聊天小软件_第2张图片

· 对话框类就只有NetChatServerDlg,与socket相关的事件处理类为ClientSocket类,而ServerSocket里面 有一个成员变量:
这里写图片描述

这个成员变量的主要作用是当我们收到转发类消息,即为MSG_SEND类型的消息时,我们可以遍历这个链表从而找到我们需要转发的客户端的socket,通过socket进行转发即可。由于有这个链表的存在,所以我们在不同类型消息实现的时候也简单了不少。
用C++/MFC实现P2P和群聊功能的聊天小软件_第3张图片

这个截图即为消息类型为MSG_LOGOIN活着MSG_SEND的处理函数,同样的,这是在应该重写的OnReceive函数里面进行的。

因为Header在上面有所介绍,所以,我们怎么找到需要服务器转发的人就是OnMSGTranslate实现的关键问题,我们已经知道我们的消息每次发送两条,第一条是消息类型type,第二条才是真正的消息,所以当我们接收到第二条消息时,我们必须对这条消息进行处理。

如“3#A#B#C#msg“,那么我们所要进行的操作就是找到A,B,C分别连接此服务器的socket,然后通过这个socket对A,B,C客户端进行转发消息,而转发的消息也同样应该是“3#A#B#C#msg“,然后客户端接收后再进行处理,稍后我会介绍当客户端接收到消息后,怎么处理,因为服务端只需要接收到消息后进行转发,所以后续的操作很少,具体的代码实现课以参照NetChatServer的ClientSocket.cpp即可。

由于MFC中的CString的类十分强大,所以在处理消息的时候,调用此类中的一些函数就可以处理,如果对CString的类使用有所不懂,那么可以参考微软的官方参考手册即可。那么当一个连接断开,那么相应的,我们也需要销毁该套接字,那么,直接调用CSocket::OnClose();相应的,应该在服务端文本框界面上有所显示(和登陆一样)。这些是主要功能,我们在额外功能里面增加了个人信息,这个要用到数据库,userSQL是我们自己写的数据库,在下面的额外功能里面,我会具体再介绍这个功能如何实现。

· 客户端:
项目整个头文件:
用C++/MFC实现P2P和群聊功能的聊天小软件_第4张图片

对话框类有Dlg_CHAT(私聊界面)、Dlg_LIST(在线列表界面)、GROUPCHAT(群聊界面)、MINETDlg(登陆界面)、SETTING(设置个人信息界面)。最核心的是CClientSocket这个类它是我们处理接收到的消息的类。Header类是上面已经说过的报头格式。

我们在客户端的main函数类里面,设置了一个链表,list来存储所有的对话框,结构如下:
这里写图片描述
用C++/MFC实现P2P和群聊功能的聊天小软件_第5张图片

这是我觉得我们这个项目里面最重要的一部分,因为这个链表的存在,我们处理消息的时候会更加的明确每条信息应该显示到哪个对话框里,然后就只需要在各个对话框里面处理我们所需要的信息即可。

结构体Node的中type是显示此结构体的对话框是群聊还是私聊,creative主要是处理下述情况,当A和B正在聊天,AB已经打开了聊天对话框,这时B突然下线,但是马上又上线,这个时候A打开的和B聊天的对话框是不生效的,虽然B的名字相同,但是socket连接不同,所以这个时候creative的作用就是解决当B下线时这个对话框就会失效的问题。下面的member就是得到当前这个对话框包括哪几个人聊天。格式上述截图有所介绍。

当所有的对话框结构清楚易于管理之后,对话框的很多事件处理函数就好写很多,这里我不再介绍我们对话框的事件处理,因为接触过MFC编程的都能清楚各个函数的含义,不过关于有关与消息的发送我还是简单的提一下。

首先,我们的客户端在点击登陆界面的登录按钮和进行群聊和私聊的时候点击发送按钮会触发socket进行发送的操作,在button消息处理函数里面,我们只需要规定好第二条msg的格式及内容,而type在调用send函数的时候进行规定,具体实现可以查看上述三个对话框类的事件处理函数和CClientSocket类中的LogoIn以及SendMSG函数,因为发送比较简单,所以这里不作更详细的说明,我主要来说明一下当服务器接收到消息之后应该如何处理。

服务器发送给客户端的消息也是分为2条,第一条跟上述情况一样,是规定了发送的类型,而第二条才是真正发送的消息。那么,客户端接收到消息之后,就会根据不同的消息类型分别进行处理。这里我们需要重写OnReceive函数。
用C++/MFC实现P2P和群聊功能的聊天小软件_第6张图片

其中,当收到TYPE类型为MSG_UPDATE和MSG_SEND时就会发生一系列的处理事件,其中因为我们的DLG_LIST是一个模态对话框,也就是说因为我们 每个客户端只有一个DLG_LIST,所以当我们收到的是在线用户更新的信息(MSG_UPDATE)时,我们就可以直接改变这个模态的对话框的值。而当收到的type为MSG_SEND的情况时,我们就应该找到一个对话框,让别人发送的消息在相应的对话框中显示,因为此时这些对话框是非模态的,所以有了上述的list info,这个链表将所有的对话框存起来。

然后我们收到消息之后,需要解析收到的第二条消息,它的格式上面已经做了说明,如3#A#B#C#LALALALALA,这段话就是A发送给B和C 内容为“LALALALALA“的一条消息,服务器会将这条消息转发给A,B,C,所以在A,B,C的客户端中,我们需要在相应的客户端中找到一个合适的对话框将“LALALALALA“这条消息显示。

那么,怎么找出来,想法很简单,就是首先在list里面找一个member也为3#A#B#C#的对话框放入,如果没有,就new一个member为3#A#B#C#的对话框,然后再放入,我们确实也是这样实现的,不过在找对话框时,我们应该知道3#A#B#C#与3#B#B#A#的member是一样的,所以我们应该不是简单的判断,应该要包括这种情况一起判断。

在我上面已经说到了还记得Node里面有一个creative成员变量吗?这个变量的作用就是当我们的在线用户列表出现改变的时候调用,比如B下线了,我们就应该把客户端中所有与B有关的客户端全部关闭,或者用另一种方法不予显示,显然我们采取了这个creative变量来判断,若这个对话框是活动的,就让它的值true,如果有关用户下线了,将这个值为false,具体实现我也不多说,可以查看ClientSocket.cpp。

由于我们新增了数据库,存储用户信息,并且用户名可以当做是主键,所以在登陆之时要进行判断,这些功能我会再下面的额外功能里面再做说明。

· 运行环境与部署配置(Setup and Deploy):
在windows环境下,先打开我们的服务器端(MINRO),确认自己的IP地址,然后在多台主机或一台主机上登录客户短,在登陆界面上填写服务器的IP地址,使客户端与服务器连接(确认客户机和服务器在同一网段下)然后按照软件使用进行使用即可。

结果输出(Result):
服务器:
用C++/MFC实现P2P和群聊功能的聊天小软件_第7张图片

客户端:
登陆界面:
用C++/MFC实现P2P和群聊功能的聊天小软件_第8张图片

在线用户列表界面:
用C++/MFC实现P2P和群聊功能的聊天小软件_第9张图片

P2P聊天界面:
用C++/MFC实现P2P和群聊功能的聊天小软件_第10张图片

群聊界面:
用C++/MFC实现P2P和群聊功能的聊天小软件_第11张图片

个人属性设置界面:
用C++/MFC实现P2P和群聊功能的聊天小软件_第12张图片

· 参考资料
1. http://blog.csdn.net/lh844386434/article/details/6655080
网络编程(三)—- MFC 仿QQ聊天软件
2. http://www.cnblogs.com/ziwuge/archive/2011/06/19/2084608.html
CString/string 区别及其转化
3. http://www.cnblogs.com/azraelly/archive/2012/04/14/2446914.html
C++文件操作详解(ifstream、ofstream、fstream)
4. http://blog.csdn.net/lebao82/article/details/7839580
MFC 对话框标题动态设置
5. http://wenku.baidu.com/link?url=6SfHPTeyVg97NfPojYp4KeQ463JPImsEuGICQq8oyFn-_n4DM_eZnEYyb-MsMfraRZ_U_I0X-8PdoSSB4wMj6Qm7IjeOI9zrlVFWYys7CoC
VS2010创建SQL数据库项目入门
6. http://blog.csdn.net/wangjiannuaa/article/details/6301353
MFC中IPADDRESS控件的使用
7. http://bbs.csdn.net/topics/390123676
C++有判断窗口是否显示隐藏的api
8. http://wenwen.sogou.com/z/q211369440.htm
在C++中添加一个按钮链接到一个网站
9. http://wenda.so.com/q/1370236883066568?src=9999
同时显示这两个对话框
10.http://www.cnblogs.com/oyjj/archive/2011/01/09/1931291.html
MFC 控件显示层次调整(叠放次序)和绘制控制问题
11. http://bbs.csdn.net/topics/390772928
用MFC做的登入时界面跳转的一些问题
12. http://bbs.csdn.net/topics/390010876
MFC 中使用Static Text ,字下面有背景色怎么去掉
13. http://blog.csdn.net/abidepan/article/details/7925679
MFC学习之 对话框设置背景颜色及控件透明的方法
14.http://ningmengjiabing.blog.163.com/blog/static/20484719820138162203485/
MFC picture控件显示动态/静态BMP图片

· 额外附加功能(Extra Functions)
1.数据库存放用户列表
新用户登录时,会修改数据库中的IsOnline状态。同时会读取数据库中的个性签名,以及在线/离线用户。定义格式如下:
#d# #False#请修改你的个性签名#

2.用户可以通过SETTING设置界面修改个性签名。
3.实现群聊匿名功能。
在群聊界面上有个button.点击之后会进入匿名模式,这样可以增加群聊的趣味性。

综述:

这是我们大三计算机网络课的一个final proj,主要使用的是socket编程。通过该proj,还学习到了MFC框架以及个性化界面的知识,重新复习了数据库的有关内容,并写了一个简易数据库mySQL。总的来说,功能还是比较单一,关于数据库部分还有bug。
欢迎指教!

完整代码请看
http://download.csdn.net/detail/stlst/8483823

本软件用VS2010/2013开发,如遇版本问题可尝试修改“属性->常规->平台工具集”解决。

你可能感兴趣的:(mfc)