一.原理
(1)客户端从标准输入读取数据,将数据序列化后发送至网络;
(2)服务器端使用多线程+生产者消费者模型;
- 生产者从网络中读取数据,并将读取到的用户信息添加至用户列表,将数据放至数据池中;
- 消费者从数据池读取数据,并广播给所有在用户列表中的用户。
(3)数据经过网络以后,反序列化再次发送给客户端,实现群聊功能。
二.所用技术
平台:Centos7.0,64位操作系统
语言:C/C++
编译工具:g++
序列化和反序列化工具:jsoncpp
窗口设计框架:ncurse/ncurses
其他:生产者消费者模型,信号量互斥机制,多线程编程,socket套接字编程
三.系统框架
server模块:收到用户发送的字符串以后,将用户信息存储到在线用户列表中,将数据存储到数据池中,再将数据广播给所有的在线用户;
client模块:从标准输入读取用户数据,并且将字符串序列化,发送给服务器;接收到服务器的数据以后,反序列化输出到消息输出框;
data_pool模块:数据池,存放用户发过来的数据,使用一个环形队列描述的;
window模块:显示用户界面,使用ncurses库实现;
四.具体模块
server:
部分成员函数介绍:
addrUser:将上线用户添加至online用户列表中;
delUser:将下线用户从online用户列表中删除;
RecvData:接受客户端发送到网络中的数据,并且判断用户的cmd状态是否是“QUIT”,若是“QUIT”就调用del将该用户从online用户列表中删除,若不是“QUIT”就将该用户数据存放至数据池;
SendData:将数据发送给所有在online用户列表中的用户;
部分成员变量的介绍:
std::map<int,struct sockaddr_in> online:维护一个在线用户列表,使用的是STL中的map数据结构,以ip为key值,sockaddr_in结构体为value值,可以通过ip地址查找到对应的用户;
client:
client这里定义的比较简单,进行数据的收发,但主逻辑部分就比较复杂了。
首先,我们使用的是多线程,为了使用户端聊天室的每一个部分都独立(主要分为标题,输出框,输入框)。
(1)标题部分:实现左右滚动的播放标题头部信息;
(2)输出框:输出分为用户数据和在线成员列表,并且实现满屏就清屏的效果;
(3)输入框:用户输入要发送的消息,按回车键就发送出去。
data_pool:
data_pool是实现一个数据池,将用户发来的数据都存储在数据池中,服务器要广播数据的时候,就从数据池中拿取数据;
这里使用生产者消费者模型,完成资源的同步与互斥,使用vector维护一个环形队列,生产者只在意环形队列的空格资源,消费者只在意数据资源。
window:
因为客户端是多线程并发执行数据,所以这里我们使用互斥锁来保证线程安全。
window模块主要是实现客户端界面,设计的大概效果如下:
comm:
这一部分主要实现数据的序列化和反序列化,使用C++第三方库jsoncpp来完成;
并且将序列化和反序列化进行简单的封装:
发送的数据会有昵称、学校、消息内容、状态信息,客户端将这些数据发送出去,序列化为一个字符串发送至网络中,服务器接收到数据以后,再将字符串反序列化为用户信息,进行分别存储和处理。
四.聊天效果图
项目源码:https://gitee.com/ypttest/chat_system