代码仓库:https://gitee.com/tgwTTT/linux-learning-dai/tree/master/ThreadPool

上一篇文章带领大家学习了socket编程基础今天就带领大家实战演练一下,夜也深了,博主码完也要去休息了。

核心设计思路

1. 网络通信层设计

UDP协议选择理由:

  • 实时性要求高:聊天系统对延迟敏感,UDP无连接特性更适合
  • 广播功能天然支持:UDP天然支持一对多通信模式
  • 资源消耗低:无需维护TCP连接状态,节省服务器资源

关键设计要点:

单线程事件循环:主线程专门负责消息接收,避免IO阻塞

异步处理机制:收到消息后立即交给线程池处理,不阻塞接收循环

地址信息封装:将sockaddr_in结构封装为友好的InetAddr对象

    2. 消息路由架构

    路由表管理策略:

    • 自动发现机制:首次发送消息的用户自动加入在线列表
    • 心跳检测:通过消息活跃度维持用户在线状态
    • 优雅退出:支持”QUIT”命令的规范退出处理

    3. 并发处理模型

    线程池工作模式:

    • 固定线程数:预先创建一定数量的工作线程
    • 任务队列:使用线程安全队列缓冲待处理消息
    • 条件变量同步:工作线程在无任务时自动休眠

    资源管理策略:

    连接无状态:UDP特性使得无需维护连接状态

    内存池优化:可考虑使用对象池管理频繁创建的对象

    流量控制:通过队列长度实现简单的背压控制

    下面是一些核心代码,完整代码请参考代码仓库

    核心架构:三层设计

    1. 网络层 – 精简的UDP服务

    // UDP服务器核心循环
    void runServer() {
    while (running) {
    char buffer[1024];
    sockaddr_in clientAddr;
    socklen_t addrLen = sizeof(clientAddr);

        // 接收消息
        int received = recvfrom(sockfd, buffer, sizeof(buffer), 0,
                               (sockaddr*)&clientAddr, &addrLen);
    
        if (received > 0) {
            buffer[received] = '\0';
            // 将消息交给处理线程
            threadPool.enqueue([this, clientAddr, msg = std::string(buffer)] {
                processMessage(clientAddr, msg);
            });
        }
    }

    }

    2. 业务层 – 智能路由

    // 消息处理核心
    void processMessage(sockaddr_in clientAddr, const std::string& msg) {
        // 自动注册新用户
        if (!userExists(clientAddr)) {
            addUser(clientAddr);
        }
        
        // 广播消息
        std::string formattedMsg = formatMessage(clientAddr, msg);
        broadcast(formattedMsg);
        
        // 处理退出命令
        if (msg == "QUIT") {
            removeUser(clientAddr);
        }
    }

    3. 并发层 – 高效线程池

    // 线程池工作线程
    void workerThread() {
        while (running) {
            std::function task;
            
            {
                std::unique_lock lock(queueMutex);
                // 等待任务
                condition.wait(lock, [this] { 
                    return !taskQueue.empty() || !running; 
                });
                
                if (!running) break;
                
                task = std::move(taskQueue.front());
                taskQueue.pop();
            }
            
            // 执行任务
            task();
        }
    }

    时间也不早了,如果有错误,欢迎在作者评论区留言,晚安!!!