聊天室
项目概述
这是一个基于C++开发的聊天室应用,支持多用户在线聊天、私聊、群组聊天和文件传输功能。应用采用客户端-服务器架构,使用TCP套接字进行通信,JSON格式传输数据。
主要功能
账号管理
实现登录、注册、注销
实现通过验证码登录/注册/密码找回(邮件/手机号等)(提高)
好友管理
实现好友的添加、删除、查询操作
实现显示好友在线状态
禁止不存在好友关系的用户间的私聊
实现屏蔽好友消息
实现好友间聊天
群管理
实现群组的创建、解散
实现用户申请加入群组
实现用户查看已加入的群组
实现群组成员退出已加入的群组
实现群组成员查看群组成员列表
实现群主对群组管理员的添加和删除
实现群组管理员批准用户加入群组
实现群组管理员/群主从群组中移除用户
实现群组内聊天功能
聊天功能
对于私聊和群组的聊天功能均需要实现:
实现查看历史消息记录
实现用户间在线聊天
实现在线用户对离线用户发送消息,离线用户上线后获得通知
实现在线发送文件
实现在线用户对离线用户发送文件,离线用户上线后获得通知/接收
实现用户在线时,消息的实时通知
收到好友请求
收到私聊
收到加群申请
…
项目详情
服务端的架构设计
该聊天室服务器采用基于事件驱动的多线程架构,结合了Epoll I/O多路复用技术和线程池模型,支持高并发连接。服务器实现了完整的聊天功能体系,包括用户管理、好友系统、群组管理、消息传递和文件传输等功能。

客户端架构设计
该聊天室客户端采用分层架构设计,结合面向对象编程思想,实现了与服务器的交互、用户界面管理、好友系统、群组系统和通知系统等功能。客户端通过TCP套接字与服务器通信,使用JSON格式传输数据。

主要代码实现
长度前缀协议
void sendLengthPrefixed(int fd, const json& response) {
std::string responseStr = response.dump();
uint32_t len = htonl(responseStr.size());
send(fd, &len, sizeof(len), 0);
send(fd, responseStr.c_str(), responseStr.size(), 0);
}
std::string receiveLengthPrefixed() {
// 接收长度
uint32_t len;
recv(sockfd, &len, sizeof(len), MSG_WAITALL);
len = ntohl(len);
// 接收数据
std::vector<char> buffer(len);
size_t totalReceived = 0;
while (totalReceived < len) {
ssize_t n = recv(sockfd, buffer.data() + totalReceived, len - totalReceived, 0);
if (n <= 0) break;
totalReceived += n;
}
return std::string(buffer.data(), len);
}
Epoll边缘触发(ET)模式:
// 创建epoll实例
int epoll_fd = epoll_create1(0);
// 添加socket
struct epoll_event ev;
ev.events = EPOLLIN | EPOLLET; // 边缘触发
ev.data.fd = server_fd;
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &ev);
// 事件循环
while (running) {
int n = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
for (int i = 0; i < n; i++) {
// 处理事件...
}
}
通知设置
void handlePollNotifications(const json& request,int client_sock) {
std::string username = request["username"];
cout<<username<<endl;
json response;
response["type"] = "poll_notifications_response";
// 获取并清空用户通知
std::vector<json> notifications;
{
std::lock_guard<std::mutex> lock(notifications_mutex);
if (user_notifications.find(username) != user_notifications.end()) {
notifications = user_notifications[username];
user_notifications[username].clear();
}
}
if (notifications.empty()) {
response["success"] = true;
response["message"] = "没有新通知";
} else {
response["success"] = true;
response["notifications"] = notifications;
}
sendLengthPrefixed(client_sock,response);
}
void addNotification(const std::string& username, const json& notification)
{
cout<<"notify"<<endl;
std::lock_guard<std::mutex> lock(notifications_mutex);
// 确保用户通知队列存在
if (user_notifications.find(username) == user_notifications.end()) {
user_notifications[username] = std::vector<json>();
}
user_notifications[username].push_back(notification);
}
常见bug
- json解析错误

json解析错误通常由数据类型不匹配,键名不匹配,解析的字段为空或者未定义,粘包造成
2. 多线程竞争
避免多线程争抢接收数据的关键是确保每个数据包只被一个线程处理,可以使用不同的套接字接收数据或者使用单线程接收
3. 深刻体会到架构的重要
代码架构是软件系统的骨架,它决定了系统的可扩展性、可维护性、性能和安全性等核心质量属性。一个优秀的代码架构能够降低开发成本、提升团队协作效率,并在长期演进中保持系统的稳定性。
总结
通过聊天室的实践,对线程,进程,网络通信有了更熟悉的运用和理解,通过多线程模型实现单服务器的并发消息处理,避免I/O阻塞;采用多进程架构提升系统吞吐量,并利用进程间通信(如管道、Socket或共享内存)同步用户状态构建出支持高并发、低延迟的实时聊天环境。

被折叠的 条评论
为什么被折叠?



