群聊系统项目(基于TCP、UDP实现)

最近学习了网络编程后, 写了一个基于TCP、UDP协议的群聊系统。

技术栈

      1、TCP、UDP通信
      2、生产、消费模型, 支持并发
      3、自定义协议封装数据 & json封装数据
      4、STL中无序map、vector容器使用
      5、日志管理模块 - 在线显示后台情况
      6、ncurses库绘制聊天界面

支持功能

      1、支持用户注册、登录。 注册成功后台会返回一个账号ID, 然后用户通过账号和密码进行登录, 进入聊天系统进行聊天。
      2、支持群发功能。当一方发送一次消息, 其他在线用户都可以接收到。
      3、支持在线用户显示。 当用户发送一次消息后,其他用户的在线列表就会显示该用户。

原理剖析

一、注册、登录模块

      1、注册、登录模块采用TCP协议实现。因为注册、登录模块的通信非常重要, 因此采用TCP协议是为了保证的数据传输的可靠性。 但由于是TCP,存在粘包问题, 我们采用自定义协议(自定义实现的类)来解决粘包问题。

1、自定义注册信息协议

//注册信息
struct RegInfo{
       char NickName[15]; //用户注册的姓名
       char School[20]; //学校
       char Passwd[20]; //密码
};

我们可以看出这是一个普通的类, 客户端在发送数据的时候按照RegInfo类的大小填充, 服务器端接收数据按照RegInfo类大小接收并解析。 这样就解决了粘包问题。 (当然这样也有局限性,在于我们发送和接收数据大小是有限的)。 在设计的时候,对于注册用户的个人信息和密码很重要。

2、自定义登录协议

//登录信息
       struct LoginInfo{
       uint32_t UserId; //返回用户使用的用户名
       char Passwd[20]; //密码
};

同样解决粘包问题, 用户登录时 用户ID 和 密码 非常关键。 后台需要识别用户ID是否存在且存在是否密码正确的问题等

3、自定义应答

//应答信息
struct ReplyInfo{
       int Status;
       uint32_t UserId;
};

这个协议主要时服务器给我们客户端返回的数据包信息。 同样解决粘包问题。
这个是客户端在发送注册数据包或者登录数据包后, 它需要知道服务器处理的结果如何? 是否注册成功、注册失败,登录成功,登录失败等现象,并进行下一步的决策。

以上是为了解决TCP粘包问题并且为了解决双方协商的问题。
下面我们重点说注册、登录的细节流程。

1、客户端发送注册、登录数据包时, 它先会发现1字节大小的数据包。它的目的为了让服务器端知道客户端是想注册还是登录。 (服务器端后台会根据1字节进行选择, 是用户注册协议接收下一个数据包还是登录协议接收)

#define REGISTER 0 //用户注册标识
#define LOGIN 1 //用户登录标识

如果1字节数据包发送的是0, 服务器端会进入注册处理。
如果为1, 服务器端会进入登录处理。

2、客户端发送注册请求。
在这里插入图片描述
3、客户端发送登录请求
在这里插入图片描述

二、用户管理模块

用户管理模块的功能:
1、当用户注册时,存储用户的个人信息,返回用户一个新的ID。
2、登录时判断该用户是否为合格。
3、进行聊天界面还需要判断黑户进入

我设计的用户管理模块包含的功能:1、用户注册;2、用户登录; 3、判断用户是否为黑户等接口。

其中userinfo是一个用户的类, 包含用户的个人信息, ID, 密码, 用户的地址信息,用户的状态信息。

后台采用了unordered_map容器以<ID, userInfo>为键值对构建存储用户信息,
保证可以通过ID键可以查找,修改到对应的userinfo信息。

当用户注册完毕后, 会在unordered_map中添加一个信息,并且将对应的userinfo类中的status置为已注册状态。

用户登录完毕后, 会将对应的unordered_map中对应的userinfo类中status置为已登录状态。

为什么要这样做呢?
答:标志这些状态非常关键, 我在后续会为大家演示, 我在这里大体说一下功能。
防止黑户进入聊天界面。(按照正常的逻辑来讲,只有已登录的用户才可以进入聊天界面, 然后聊天界面是UDP通信, 如果别人知道我服务器的IP地址和UDP绑定的PORT端口,那是不是可以跨过注册、登录模块,直接进入聊天模块呢??)

(聊天模块)当用户在聊天界面第一次消息后, 我们会先检查该用户信息, 然后判断该用户的状态status是否为已登录的状态, 如果是,我们会在userinfo类中填充用户当前的地址信息, 然后把用户的状态status置为已在线状态, 并且将该用户userinfo添加到在线用户列表onlinelist中。(是一个vector<userinfo容器, 它专门存储当前在线用户, 功能在于转发所有在线用户,形成群发的特点。后续介绍)
       如果用户不止一次发送过消息, 二次或多次给我们发送消息时,我们会先检查,然后判断用户userinfo的状态为已在线状态。 就不用管了。 这种用户也是合格的。

三、生产、消费模型

生产线程 + 消费线程 + 线程安全的队列。
(实现需要互斥锁 + 条件变量 + STL中queue)

生产、消费模型的处理逻辑:

一开始线程安全队列为空, 生产线程和消费线程一开始都会创建, 由于一开始队列为空, 因此消费线程会处于阻塞当中,当生产线程把需要处理的数据添加到线程安全队列中后,会唤醒消费线程去取数据处理。 当消费线程处理完毕之后会唤醒生产线程去添加数据。 这样形成一种良性的循环。 对于队列的操作需要保证同步和互斥。

这是线程安全处理的方式之一。 它的优点可以解决多线程带来的高并发问题。
(高并发:一个处理器处理,当存在大量的线程就绪准备使用CPU时, 这种的情况就是高并发,高并发存在的问题线程切换,线程过多,频繁的切换,切换的时候会加载相应的信息, 最终使得整个业务的处理缓慢)
生产、消费模型当队列满了时候生产线程会阻塞(阻塞的线程不会竞争CPU, 它会在阻塞的队列中,等待唤醒),消费线程也同理。 可以有效解决并发问题。

这种模型在CS模型中经常使用。

在这个项目中同样也是用到了它, 我们生产线程负责把用户发来的数据添加到线程安全队列中,去唤醒消费线程去完成对所有在线用户的转发, 从而形成群发的效果。

这个时候我们会用到上述的用户管理模块的 用户在线列表vector<userinfo。
它里面保存的时在线的用户userinfo类。

这个时候只需要循环调用sendto接口发送即可,即实现群发。

四、聊天模块

服务器端: 聊天模块就是UDP通信 + 生产消费模型

当客户端的聊天模块UDPsocket收到了数据包, 这时候会收到json格式的string对象recv_string, 我们需要进行json反序列化将用户发送的数据内容解析出来。

取出来的ID用来用户管理模块的用户检查 (已在上面解释过)。

如果检查用户ID不合格, 我们会忽略处理这条消息。

如果合适我们会将处理, 将json格式的 recv_string 对象添加到生产、消费模型中的线程安全队列, 从而唤醒消费线程去处理。(已在上面解释过)

客户端:当用户登录成功之后会进入聊天界面, 聊天界面分为3块, 接收消息区; 发送消息区;显示在线用户列表区;当然还有顶部的介绍区(虽然有点尴尬!)

我们聊天模块采用UDP通信, UDP通信的好处: 数据报传输, 速度快。

对于发送的数据我们采用 json 封装 和 对应的解析。
需要json封装的数据有{ 用户的姓名; ID; 发送的内容 }
(用户的姓名在后续的在线列表显示有用, ID用于检查用户, 发送内容,聊天嘛,不能不说啥吧)

当用户收到服务器端的数据包时, 它也是接收的json格式的数据。
对其解析后会到 发送用户的姓名; 发送用户的消息内容。
将发送用户的姓名在 在线用户显示区显示。
将发送用户的数据在 接收消息区显示。

从而在客户端会形成聊天的简单样子。 但是核心就是这样实现的。

五、日志系统

在项目开发中, 日志系统必不可少, 我是第一次用到它, 用过就说好。

它会标志我们服务器后台每一次的操作流程。
如果有问题可以查看日志系统进行分析, 准备定位到错误。 尤其是在大型开发中。
在这里插入图片描述
通过日志系统我们看出我们程序执行到那块, 执行的怎么样, 那些操作没做等问题。

六、演示:

注册登录界面:
在这里插入图片描述
交互界面
在这里插入图片描述
后台日志显示
在这里插入图片描述

源码链接:

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值