基于C++实现的聊天室

项目内容

本项目基于C++实现了一个具有群聊功能的聊天室。客户端基于QT实现,服务端基于epoll实现。目前已上传到https://github.com/cswen-scut/chatroom,喜欢的朋友记得给个星星哦O(∩_∩)O。

项目演示

在这里插入图片描述

技术点

  • 客户端涉及到的技术点

    • 常用QT控件(QWidget, QListWidget, QLabel, QPushButton)
    • QT信号与槽
    • QJsonObject完成json数据的解析
    • QT多线程
    • QTcpSocket连接服务器
  • 服务端涉及到的技术点

    • epoll多路IO转接机制
    • 常用STL(vector, map)
    • 文件读写(fstream)
    • jsoncpp解析json数据
    • MySQL基本操作

实现的功能

  • 注册
  • 单点登录
  • 登出
  • 群聊(支持文本和图片的传送)
  • 上线下线公告
  • 在线用户记录

通信协议

为保证数据能够被正确发送和接收,本项目还自定义了一个协议

  • 开始1B表示这个数据包是注册请求、登录请求、发送请求、登出请求等
  • 接下来2B表示用户的账号
  • 接下来1B表示数据包的数据格式,文本或图片
  • 接下来4B表示数据的大小
  • 最后就是真实数据了

遇到的问题及解决方案

1. 服务端端口被占用问题

问题描述:

服务端强制关闭后TCP连接进入TIME_WAIT状态,此状态持续2MSL(大概40多秒),由于端口被占用,若此时若再次启动服务端,会失败。

解决方案:

通过setsockopt函数实现端口复用。

2. 数据包"粘包"问题

问题描述:

TCP是流式协议,所传输的数据没有明确的界线,需要用户自己区分。

解决方案:

在接收数据时,先解析协议头部,根据头部数据大小字段来决定接收多少数据,然后循环接收数据,直到接收完该数据大小的包后再接收下一个包。

3. QT readyRead信号丢失问题

问题描述:

若服务端发送给客户端的数据较大,且发送速度较快,客户端可能来不及接收完本次readyRead信号的bytesAvailable大小的数据,此时服务端却在不停地发,可能会造成客户端readyRead信号的丢失,从而导致接收数据不全。

解决方案:

使用确认机制,即客户端每读完一个readyRead信号所携带的数据后,给服务端发送一个确认包,告诉服务端自己已经接收了多少数据,然后服务端再接着发下一部分的数据,直到接收完数据。

4. 客户端发送数据与接收数据的冲突问题

问题描述:

若客户端与服务端仅建立一个连接,那么当客户端在接收数据时,若客户端此时向服务端发送聊天数据,服务端本应接收客户端的确认包,但是却接收了客户端的聊天数据,从而造成确认信息异常。

解决方案:

客户端与服务端建立两个连接,一个用于写数据,一个用于读数据。

5. 客户端强制退出问题

问题描述:

客户端在接收数据时,强制退出了,服务端由于发给客户端的数据没有收到确认,在read确认包时进入了阻塞状态。

解决方案:

每次向客户端发送数据时,先用getsockopt获取客户端的连接状态,若客户端的连接状态不是ESTABLISHED,则直接结束发送,并取消监听客户端的fd。

总结

本项目的主要目的是熟悉C++和Linux网络编程,目前还有很多不完善之处,例如服务端仅采用单线程实现,这样效率会很低,后续考虑引入线程池。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值