基于tcp的聊天室

聊天室

项目概述

这是一个基于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

  1. json解析错误
    在这里插入图片描述

json解析错误通常由数据类型不匹配,键名不匹配,解析的字段为空或者未定义,粘包造成
2. 多线程竞争
避免多线程争抢接收数据的关键是​​确保每个数据包只被一个线程处理,可以使用不同的套接字接收数据或者使用单线程接收
3. 深刻体会到架构的重要
代码架构是软件系统的骨架,它决定了系统的可扩展性、可维护性、性能和安全性等核心质量属性。一个优秀的代码架构能够降低开发成本、提升团队协作效率,并在长期演进中保持系统的稳定性。

总结

通过聊天室的实践,对线程,进程,网络通信有了更熟悉的运用和理解,通过多线程模型实现单服务器的并发消息处理,避免I/O阻塞;采用多进程架构提升系统吞吐量,并利用进程间通信(如管道、Socket或共享内存)同步用户状态构建出支持高并发、低延迟的实时聊天环境。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值