epoll+线程池
1、初始化线程池
2、获取时间
3、首次响应客户端连接
4、创建epoll实例
5、创建任务队列
6、处理新连接的任务
7、消费者函数
8、从队列里取任务
9、确认线程是否存活
10、生产者添加任务
11、向任务队列中添加任务
12、管理者线程函数
13、处理客户端请求任务函数
14、epoll_listen监听套接字
15、创建线程池
16、主函数
编译
gcc *.c -I../include -L. -lthread_pool -lpthread -o app
测试
nc 169.254.196.205 8080
总结
以下是**所有函数的分类总结**,按 **“模块职责+核心逻辑”** 梳理,帮你快速关联记忆:
### **一、网络初始化模块(TCP 服务器启动)**
| 函数名 | 功能 & 核心逻辑 | 作用 |
|-----------------|-----------------------------------------------------------------------------|----------------------------------------------------------------------|
| `INET_INIT` | 创建 TCP 套接字 → 填充 `sockaddr_in`(绑定任意 IP、端口转网络序) → `bind` → `listen` | 启动 TCP 监听,返回监听套接字,是服务器的**入口基础** |
### **二、时间处理模块(辅助工具)**
| 函数名 | 功能 & 核心逻辑 | 作用 |
|--------------|--------------------------------------------------------------------------|----------------------------------------------------------------------|
| `GET_TIME` | 用 `time_t` 获取当前时间 → `ctime_r`(线程安全)转字符串 → 移除换行符(`\n` 改 `\0`) | 为日志、响应生成**格式化时间字符串**,避免线程安全问题 |
### **三、客户端交互模块(连接响应、请求处理)**
| 函数名 | 功能 & 核心逻辑 | 作用 |
|-------------------|-----------------------------------------------------------------------------|----------------------------------------------------------------------|
| `FIRST_RESPONSE` | 调用 `GET_TIME` 获取时间 → 拼接客户端 IP/端口 → `send` 欢迎消息(带 `MSG_NOSIGNAL` 避免 `SIGPIPE`) | 客户端**首次连接时的响应**,告知连接成功 |
| `response_task` | 循环非阻塞 `recv`(`MSG_DONTWAIT`) → 解析命令(如 `time` 则返回当前时间) → 连接关闭时清理 `epoll` | 处理客户端**持续数据交互**,支持命令响应、连接释放 |
### **四、epoll 多路复用模块(高效 IO 监听)**
| 函数名 | 功能 & 核心逻辑 | 作用 |
|---------------|----------------------------------------------------------------------------|----------------------------------------------------------------------|
| `epoll_init` | `epoll_create` 创建实例 → 构造 `epoll_event`(边缘触发 `EPOLLET` + 读事件 `EPOLLIN`) → `epoll_ctl_add` 监听套接字 | 初始化 epoll,让服务器**高效监听新连接/数据事件** |
| `epoll_listen`| `epoll_wait` 阻塞等事件 → 区分“新连接”(提交 `accept_task`)和“客户端数据”(提交 `response_task`) → 循环处理 | 服务器**事件分发核心**,将 IO 事件转为线程池任务 |
### **五、任务队列模块(生产者-消费者解耦)**
| 函数名 | 功能 & 核心逻辑 | 作用 |
|---------------|-----------------------------------------------------------------------------|----------------------------------------------------------------------|
| `queue_create`| 分配队列内存(控制结构 + 任务数组) → 初始化 `front`/`rear`/`cur`/`max`(环形队列) | 创建**线程安全的任务缓冲区**,解耦生产者(如 epoll)和消费者(工作线程) |
| `queue_en` | 检查队列满 → 任务加入队尾(`rear` 循环后移:`rear=(rear+1)%max`) → `cur++` | 生产者**安全入队**,用环形队列避免“假溢出” |
| `queue_de` | 检查队列空 → 取出队首任务(`front` 循环后移:`front=(front+1)%max`) → `cur--` | 消费者**安全出队**,保证任务有序执行 |
### **六、线程池模块(并行任务处理)**
#### **1. 线程池创建 & 基础**
| 函数名 | 功能 & 核心逻辑 | 作用 |
|-----------------------|-----------------------------------------------------------------------------|----------------------------------------------------------------------|
| `threads_pool_create` | 分配线程池内存 → 初始化状态(核心线程、最大线程、任务队列等) → 创建**核心工作线程**(`customer`)和**管理器线程**(`manager`) | 构建线程池基础,是**并行处理的核心载体** |
#### **2. 任务生产(生产者逻辑)**
| 函数名 | 功能 & 核心逻辑 | 作用 |
|---------------------|-----------------------------------------------------------------------------|----------------------------------------------------------------------|
| `producer_add_task` | 检查线程池运行状态 → 加锁保护队列 → 队列满则等 `not_full` → 入队后通知 `not_empty` → 解锁 | 生产者(如 `epoll_listen`)**安全提交任务**到线程池 |
| `accept_task` | `accept` 新连接 → 解析客户端 IP/端口(`inet_ntop`/`ntohs`) → 新套接字加入 epoll → 调用 `FIRST_RESPONSE` | 处理**新客户端连接的任务逻辑**,是线程池的典型“生产任务” |
#### **3. 任务消费(工作线程逻辑)**
| 函数名 | 功能 & 核心逻辑 | 作用 |
|------------|-----------------------------------------------------------------------------|----------------------------------------------------------------------|
| `customer` | 加锁 → 队列空则等 `not_empty` → 检查退出条件 → 出队执行任务(`tmp.work(tmp.arg)`) → 解锁更新状态 | 线程池的**消费者**,循环从队列取任务并行执行 |
#### **4. 线程池管理(动态调整)**
| 函数名 | 功能 & 核心逻辑 | 作用 |
|-----------|-----------------------------------------------------------------------------|----------------------------------------------------------------------|
| `manager` | 监控线程池状态(活跃线程、忙碌线程、任务队列) → 任务满/忙碌比例高则**扩容**,空闲多则**缩容** → 写日志 | 动态优化线程池资源,避免线程过多/过少影响性能 |
### **七、辅助工具函数**
| 函数名 | 功能 & 核心逻辑 | 作用 |
|----------------|----------------------------------------------------------------------|----------------------------------------------------------------------|
| `thread_alive` | 用 `pthread_kill(tid, 0)` 检查线程状态 → `ESRCH` 错误表示线程已终止 | 判断线程是否存活,为 `manager` 动态调整提供依据 |
### **记忆口诀(串联核心流程)**
1. **启动**:`INET_INIT` 建监听 → `epoll_init` 开多路 → `threads_pool_create` 起线程池
2. **事件循环**:`epoll_listen` 等事件 → 新连接/数据转任务 → `producer_add_task` 入队列
3. **任务处理**:`customer` 线程取任务 → 执行 `accept_task`/`response_task` → 交互/响应客户端
4. **动态优化**:`manager` 监控状态 → 自动扩容/缩容 → 平衡性能与资源
通过 **“模块分类 + 核心逻辑 + 流程串联”**,可快速记住每个函数的职责和协作关系,重点关注 **epoll 事件分发、线程池生产消费、动态调整** 这三条主线!