news 2026/4/18 5:02:00

Linux网络编程为什么需要基于epoll的Reactor封装

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux网络编程为什么需要基于epoll的Reactor封装

第一部分:为什么需要Reactor封装

1.1 当前限制

// 当前是同步/阻塞模型 while (running) { socket_t client = sock_accept(server, NULL, 1000); // 阻塞或轮询 if (client != SOCKET_INVALID) { // 每个连接需要一个线程 pthread_create(&thread, NULL, handle_client, (void*)client); } }

1.2 Reactor的优势

  • 单线程处理数千连接(C10K问题)

  • 事件驱动,无阻塞等待

  • 资源利用率高

  • 编程模型清晰

第二部分:Reactor模块设计

2.1 文件结构扩展

socket_lib/ ├── include/ │ ├── socket.h # 基础Socket接口(已有) │ └── reactor.h # Reactor事件驱动接口(新增) ├── src/ │ ├── socket_core.c # 基础Socket │ ├── socket_io.c # 数据IO │ ├── socket_opt.c # 选项设置 │ ├── socket_util.c # 工具函数 │ └── reactor.c # Reactor实现(新增) └── examples/ ├── echo_server.c # 传统服务器 └── reactor_server.c # Reactor服务器(新增)

2.2 Reactor头文件设计 (reactor.h)

/** * @file reactor.h * @brief Reactor事件驱动框架 * * 基于epoll的高性能事件驱动框架,支持水平触发和边沿触发。 * 提供简洁的API用于构建高性能网络服务器。 * * @version 1.0 * @date 2024-01-01 */ ​ #ifndef REACTOR_H #define REACTOR_H ​ #include "socket.h" #include <stdbool.h> #include <stddef.h> ​ #ifdef __cplusplus extern "C" { #endif ​ /* ==================== 基本类型 ==================== */ ​ /** * @brief Reactor句柄 */ typedef struct reactor* reactor_t; ​ /** * @brief 事件类型 */ typedef enum { REACTOR_EVENT_NONE = 0x00, /**< 无事件 */ REACTOR_EVENT_READ = 0x01, /**< 可读事件 */ REACTOR_EVENT_WRITE = 0x02, /**< 可写事件 */ REACTOR_EVENT_ERROR = 0x04, /**< 错误事件 */ REACTOR_EVENT_HUP = 0x08, /**< 挂起事件 */ REACTOR_EVENT_ALL = 0x0F /**< 所有事件 */ } reactor_event_t; ​ /** * @brief 触发模式 */ typedef enum { REACTOR_TRIGGER_LEVEL, /**< 水平触发(默认) */ REACTOR_TRIGGER_EDGE /**< 边沿触发 */ } reactor_trigger_t; ​ /** * @brief 事件回调函数类型 * * @param reactor Reactor实例 * @param fd 文件描述符 * @param events 发生的事件 * @param user_data 用户数据 */ typedef void (*reactor_callback_t)(reactor_t reactor, int fd, reactor_event_t events, void* user_data); ​ /* ==================== Reactor生命周期 ==================== */ ​ /** * @brief 创建Reactor * * @param max_events 最大事件数(默认1024) * @param trigger 触发模式 * @return reactor_t Reactor句柄,NULL失败 */ reactor_t reactor_create(int max_events, reactor_trigger_t trigger); ​ /** * @brief 销毁Reactor * * @param reactor Reactor句柄 */ void reactor_destroy(reactor_t reactor); ​ /** * @brief 运行Reactor事件循环 * * @param reactor Reactor句柄 * @param timeout_ms 超时时间(毫秒,-1阻塞,0立即返回) * @return int 处理的事件数,-1错误 */ int reactor_run(reactor_t reactor, int timeout_ms); ​ /** * @brief 停止Reactor事件循环 * * @param reactor Reactor句柄 */ void reactor_stop(reactor_t reactor); ​ /* ==================== 事件管理 ==================== */ ​ /** * @brief 添加事件监视 * * @param reactor Reactor句柄 * @param fd 文件描述符 * @param events 监视的事件 * @param callback 事件回调 * @param user_data 用户数据 * @return int 0成功,-1失败 */ int reactor_add(reactor_t reactor, int fd, reactor_event_t events, reactor_callback_t callback, void* user_data); ​ /** * @brief 修改事件监视 * * @param reactor Reactor句柄 * @param fd 文件描述符 * @param events 新的事件 * @param user_data 新的用户数据(NULL保持原样) * @return int 0成功,-1失败 */ int reactor_modify(reactor_t reactor, int fd, reactor_event_t events, void* user_data); ​ /** * @brief 删除事件监视 * * @param reactor Reactor句柄 * @param fd 文件描述符 * @return int 0成功,-1失败 */ int reactor_remove(reactor_t reactor, int fd); ​ /** * @brief 检查fd是否在Reactor中 * * @param reactor Reactor句柄 * @param fd 文件描述符 * @return bool true存在,false不存在 */ bool reactor_contains(reactor_t reactor, int fd); ​ /* ==================== 定时器支持 ==================== */ ​ /** * @brief 定时器回调函数类型 * * @param reactor Reactor实例 * @param timer_id 定时器ID * @param user_data 用户数据 */ typedef void (*reactor_timer_callback_t)(reactor_t reactor, int timer_id, void* user_data); ​ /** * @brief 添加定时器 * * @param reactor Reactor句柄 * @param interval_ms 间隔时间(毫秒) * @param callback 定时器回调 * @param user_data 用户数据 * @param repeat 是否重复 * @return int 定时器ID,-1失败 */ int reactor_add_timer(reactor_t reactor, int interval_ms, reactor_timer_callback_t callback, void* user_data, bool repeat); ​ /** * @brief 删除定时器 * * @param reactor Reactor句柄 * @param timer_id 定时器ID * @return int 0成功,-1失败 */ int reactor_remove_timer(reactor_t reactor, int timer_id); ​ /* ==================== 工具函数 ==================== */ ​ /** * @brief 获取Reactor中监视的fd数量 * * @param reactor Reactor句柄 * @return int fd数量 */ int reactor_count(reactor_t reactor); ​ /** * @brief 设置用户数据 * * @param reactor Reactor句柄 * @param fd 文件描述符 * @param user_data 用户数据 * @return int 0成功,-1失败 */ int reactor_set_userdata(reactor_t reactor, int fd, void* user_data); ​ /** * @brief 获取用户数据 * * @param reactor Reactor句柄 * @param fd 文件描述符 * @return void* 用户数据 */ void* reactor_get_userdata(reactor_t reactor, int fd); ​ #ifdef __cplusplus } #endif ​ #endif /* REACTOR_H */

2.3 Reactor实现 (reactor.c)

/** * @file reactor.c * @brief Reactor事件驱动框架实现 * * 基于epoll实现高性能事件驱动,支持定时器和事件回调。 * * @version 1.0 * @date 2024-01-01 */ ​ #include "reactor.h" #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/epoll.h> #include <sys/timerfd.h> #include <time.h> #include <errno.h> ​ /* ==================== 内部数据结构 ==================== */ ​ /** * @brief 事件上下文 */ typedef struct { reactor_callback_t callback; /**< 事件回调 */ void* user_data; /**< 用户数据 */ reactor_event_t events; /**< 监视的事件 */ bool active; /**< 是否活跃 */ } event_context_t; ​ /** * @brief 定时器上下文 */ typedef struct { reactor_timer_callback_t callback; /**< 定时器回调 */ void* user_data; /**< 用户数据 */ int interval_ms; /**< 间隔时间 */ bool repeat; /**< 是否重复 */ int timer_fd; /**< 定时器fd */ } timer_context_t; ​ /** * @brief Reactor内部结构 */ struct reactor { int epoll_fd; /**< epoll文件描述符 */ int max_events; /**< 最大事件数 */ bool running; /**< 是否运行中 */ reactor_trigger_t trigger; /**< 触发模式 */ /* 事件管理 */ struct epoll_event* events; /**< 事件数组 */ event_context_t* contexts; /**< 事件上下文数组 */ int context_size; /**< 上下文数组大小 */ int context_count; /**< 活跃上下文数量 */ /* 定时器管理 */ timer_context_t* timers; /**< 定时器数组 */ int timer_size; /**< 定时器数组大小 */ int timer_count; /**< 定时器数量 */ int next_timer_id; /**< 下一个定时器ID */ /* 统计信息 */ struct { uint64_t events_processed; /**< 处理的事件总数 */ uint64_t timers_triggered; /**< 触发的定时器数 */ uint64_t callbacks_called; /**< 调用的回调数 */ } stats; /* 互斥锁 */ common_mutex_t mutex; }; ​ /* ==================== 内部辅助函数 ==================== */ ​ /** * @brief 将事件类型转换为epoll事件 * * @param events 事件类型 * @return uint32_t epoll事件 */ static uint32_t events_to_epoll(reactor_event_t events) { uint32_t epoll_events = 0; if (events & REACTOR_EVENT_READ) { epoll_events |= EPOLLIN; } if (events & REACTOR_EVENT_WRITE) { epoll_events |= EPOLLOUT; } if (events & REACTOR_EVENT_ERROR) { epoll_events |= EPOLLERR; } if (events & REACTOR_EVENT_HUP) { epoll_events |= EPOLLHUP | EPOLLRDHUP; } return epoll_events; } ​ /** * @brief 将epoll事件转换为事件类型 * * @param epoll_events epoll事件 * @return reactor_event_t 事件类型 */ static reactor_event_t epoll_to_events(uint32_t epoll_events) { reactor_event_t events = REACTOR_EVENT_NONE; if (epoll_events & EPOLLIN) { events |= REACTOR_EVENT_READ; } if (epoll_events & EPOLLOUT) { events |= REACTOR_EVENT_WRITE; } if (epoll_events & EPOLLERR) { events |= REACTOR_EVENT_ERROR; } if (epoll_events & (EPOLLHUP | EPOLLRDHUP)) { events |= REACTOR_EVENT_HUP; } return events; } ​ /** * @brief 确保上下文数组有足够空间 * * @param reactor Reactor实例 * @param fd 文件描述符 * @return int 0成功,-1失败 */ static int ensure_context_capacity(reactor_t reactor, int fd) { if (fd < reactor->context_size) { return 0; } int new_size = reactor->context_size * 2; if (new_size <= fd) { new_size = fd + 100; /* 额外100个空间 */ } event_context_t* new_contexts = common_realloc(reactor->contexts, new_size * sizeof(event_context_t)); if (!new_contexts) { return -1; } /* 初始化新分配的空间 */ for (int i = reactor->context_size; i < new_size; i++) { new_contexts[i].callback = NULL; new_contexts[i].user_data = NULL; new_contexts[i].events = REACTOR_EVENT_NONE; new_contexts[i].active = false; } reactor->contexts = new_contexts; reactor->context_size = new_size; return 0; } ​ /** * @brief 添加epoll事件 * * @param reactor Reactor实例 * @param fd 文件描述符 * @param events 事件 * @param user_data 用户数据 * @return int 0成功,-1失败 */ static int add_epoll_event(reactor_t reactor, int fd, reactor_event_t events, void* user_data) { struct epoll_event ev; memset(&ev, 0, sizeof(ev)); ev.events = events_to_epoll(events); ev.data.fd = fd; if (reactor->trigger == REACTOR_TRIGGER_EDGE) { ev.events |= EPOLLET; /* 边沿触发 */ } if (epoll_ctl(reactor->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) { if (errno == EEXIST) { /* 已存在,改为修改 */ if (epoll_ctl(reactor->epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) { return -1; } } else { return -1; } } return 0; } ​ /** * @brief 创建定时器fd * * @param interval_ms 间隔时间(毫秒) * @return int 定时器fd,-1失败 */ static int create_timer_fd(int interval_ms) { int timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); if (timer_fd < 0) { return -1; } struct itimerspec its; memset(&its, 0, sizeof(its)); its.it_value.tv_sec = interval_ms / 1000; its.it_value.tv_nsec = (interval_ms % 1000) * 1000000; if (interval_ms > 0) { its.it_interval = its.it_value; /* 重复间隔 */ } if (timerfd_settime(timer_fd, 0, &its, NULL) < 0) { close(timer_fd); return -1; } return timer_fd; } ​ /** * @brief 处理定时器事件 * * @param reactor Reactor实例 * @param timer_fd 定时器fd */ static void process_timer_event(reactor_t reactor, int timer_fd) { /* 读取定时器过期次数 */ uint64_t expirations; ssize_t s = read(timer_fd, &expirations, sizeof(expirations)); if (s != sizeof(expirations)) { LOG_WARN("REACTOR", "Failed to read timerfd"); return; } /* 查找对应的定时器 */ for (int i = 0; i < reactor->timer_count; i++) { if (reactor->timers[i].timer_fd == timer_fd && reactor->timers[i].callback) { reactor->stats.timers_triggered++; reactor->timers[i].callback(reactor, i, reactor->timers[i].user_data); /* 如果不是重复定时器,删除它 */ if (!reactor->timers[i].repeat) { reactor_remove_timer(reactor, i); } break; } } } ​ /* ==================== 公开API实现 ==================== */ ​ /** * @brief 创建Reactor */ reactor_t reactor_create(int max_events, reactor_trigger_t trigger) { if (max_events <= 0) { max_events = 1024; } reactor_t reactor = common_calloc(1, sizeof(struct reactor)); if (!reactor) { return NULL; } /* 创建epoll实例 */ reactor->epoll_fd = epoll_create1(EPOLL_CLOEXEC); if (reactor->epoll_fd < 0) { common_free(reactor); return NULL; } /* 分配事件数组 */ reactor->max_events = max_events; reactor->events = common_calloc(max_events, sizeof(struct epoll_event)); if (!reactor->events) { close(reactor->epoll_fd); common_free(reactor); return NULL; } /* 初始化上下文数组 */ reactor->context_size = 1024; reactor->contexts = common_calloc(reactor->context_size, sizeof(event_context_t)); if (!reactor->contexts) { common_free(reactor->events); close(reactor->epoll_fd); common_free(reactor); return NULL; } /* 初始化定时器数组 */ reactor->timer_size = 32; reactor->timers = common_calloc(reactor->timer_size, sizeof(timer_context_t)); if (!reactor->timers) { common_free(reactor->contexts); common_free(reactor->events); close(reactor->epoll_fd); common_free(reactor); return NULL; } /* 初始化其他字段 */ reactor->running = false; reactor->trigger = trigger; reactor->context_count = 0; reactor->timer_count = 0; reactor->next_timer_id = 0; memset(&reactor->stats, 0, sizeof(reactor->stats)); /* 创建互斥锁 */ reactor->mutex = common_mutex_create(); if (!reactor->mutex) { common_free(reactor->timers); common_free(reactor->contexts); common_free(reactor->events); close(reactor->epoll_fd); common_free(reactor); return NULL; } LOG_DEBUG("REACTOR", "Reactor created: max_events=%d, trigger=%d", max_events, trigger); return reactor; } ​ /** * @brief 销毁Reactor */ void reactor_destroy(reactor_t reactor) { if (!reactor) { return; } LOG_DEBUG("REACTOR", "Destroying reactor"); /* 停止事件循环 */ reactor_stop(reactor); /* 关闭所有定时器 */ for (int i = 0; i < reactor->timer_count; i++) { if (reactor->timers[i].timer_fd >= 0) { close(reactor->timers[i].timer_fd); } } /* 关闭epoll */ if (reactor->epoll_fd >= 0) { close(reactor->epoll_fd); } /* 销毁互斥锁 */ if (reactor->mutex) { common_mutex_destroy(reactor->mutex); } /* 释放内存 */ common_free(reactor->timers); common_free(reactor->contexts); common_free(reactor->events); common_free(reactor); LOG_DEBUG("REACTOR", "Reactor destroyed"); } ​ /** * @brief 运行Reactor事件循环 */ int reactor_run(reactor_t reactor, int timeout_ms) { if (!reactor) { errno = EINVAL; return -1; } common_mutex_lock(reactor->mutex); reactor->running = true; common_mutex_unlock(reactor->mutex); LOG_DEBUG("REACTOR", "Starting reactor event loop"); while (reactor->running) { /* 等待事件 */ int nfds = epoll_wait(reactor->epoll_fd, reactor->events, reactor->max_events, timeout_ms); if (nfds < 0) { if (errno == EINTR) { continue; /* 被信号中断 */ } LOG_ERROR("REACTOR", "epoll_wait failed: %s", strerror(errno)); break; } if (nfds == 0) { /* 超时,继续循环 */ continue; } /* 处理事件 */ for (int i = 0; i < nfds; i++) { int fd = reactor->events[i].data.fd; reactor_event_t events = epoll_to_events(reactor->events[i].events); /* 检查是否是定时器fd */ bool is_timer = false; for (int j = 0; j < reactor->timer_count; j++) { if (reactor->timers[j].timer_fd == fd) { process_timer_event(reactor, fd); is_timer = true; break; } } if (is_timer) { continue; } /* 处理普通事件 */ if (fd >= 0 && fd < reactor->context_size && reactor->contexts[fd].active && reactor->contexts[fd].callback) { reactor->stats.events_processed++; reactor->stats.callbacks_called++; reactor->contexts[fd].callback(reactor, fd, events, reactor->contexts[fd].user_data); } } } common_mutex_lock(reactor->mutex); reactor->running = false; common_mutex_unlock(reactor->mutex); LOG_DEBUG("REACTOR", "Reactor event loop stopped"); return 0; } ​ /** * @brief 停止Reactor事件循环 */ void reactor_stop(reactor_t reactor) { if (!reactor) { return; } common_mutex_lock(reactor->mutex); reactor->running = false; common_mutex_unlock(reactor->mutex); LOG_DEBUG("REACTOR", "Reactor stop requested"); } ​ /** * @brief 添加事件监视 */ int reactor_add(reactor_t reactor, int fd, reactor_event_t events, reactor_callback_t callback, void* user_data) { if (!reactor || fd < 0 || !callback) { errno = EINVAL; return -1; } common_mutex_lock(reactor->mutex); /* 确保容量 */ if (ensure_context_capacity(reactor, fd) < 0) { common_mutex_unlock(reactor->mutex); return -1; } /* 添加epoll事件 */ if (add_epoll_event(reactor, fd, events, user_data) < 0) { common_mutex_unlock(reactor->mutex); return -1; } /* 保存上下文 */ reactor->contexts[fd].callback = callback; reactor->contexts[fd].user_data = user_data; reactor->contexts[fd].events = events; reactor->contexts[fd].active = true; reactor->context_count++; common_mutex_unlock(reactor->mutex); LOG_DEBUG("REACTOR", "Added fd=%d to reactor, events=0x%x", fd, events); return 0; } ​ /** * @brief 修改事件监视 */ int reactor_modify(reactor_t reactor, int fd, reactor_event_t events, void* user_data) { if (!reactor || fd < 0 || fd >= reactor->context_size) { errno = EINVAL; return -1; } common_mutex_lock(reactor->mutex); if (!reactor->contexts[fd].active) { common_mutex_unlock(reactor->mutex); errno = ENOENT; return -1; } /* 修改epoll事件 */ struct epoll_event ev; memset(&ev, 0, sizeof(ev)); ev.events = events_to_epoll(events); ev.data.fd = fd; if (reactor->trigger == REACTOR_TRIGGER_EDGE) { ev.events |= EPOLLET; } if (epoll_ctl(reactor->epoll_fd, EPOLL_CTL_MOD, fd, &ev) < 0) { common_mutex_unlock(reactor->mutex); return -1; } /* 更新上下文 */ reactor->contexts[fd].events = events; if (user_data) { reactor->contexts[fd].user_data = user_data; } common_mutex_unlock(reactor->mutex); LOG_DEBUG("REACTOR", "Modified fd=%d in reactor, events=0x%x", fd, events); return 0; } ​ /** * @brief 删除事件监视 */ int reactor_remove(reactor_t reactor, int fd) { if (!reactor || fd < 0 || fd >= reactor->context_size) { errno = EINVAL; return -1; } common_mutex_lock(reactor->mutex); if (!reactor->contexts[fd].active) { common_mutex_unlock(reactor->mutex); errno = ENOENT; return -1; } /* 从epoll删除 */ if (epoll_ctl(reactor->epoll_fd, EPOLL_CTL_DEL, fd, NULL) < 0) { common_mutex_unlock(reactor->mutex); return -1; } /* 清除上下文 */ reactor->contexts[fd].callback = NULL; reactor->contexts[fd].user_data = NULL; reactor->contexts[fd].events = REACTOR_EVENT_NONE; reactor->contexts[fd].active = false; reactor->context_count--; common_mutex_unlock(reactor->mutex); LOG_DEBUG("REACTOR", "Removed fd=%d from reactor", fd); return 0; } ​ /** * @brief 添加定时器 */ int reactor_add_timer(reactor_t reactor, int interval_ms, reactor_timer_callback_t callback, void* user_data, bool repeat) { if (!reactor || interval_ms <= 0 || !callback) { errno = EINVAL; return -1; } common_mutex_lock(reactor->mutex); /* 检查是否需要扩展定时器数组 */ if (reactor->timer_count >= reactor->timer_size) { int new_size = reactor->timer_size * 2; timer_context_t* new_timers = common_realloc(reactor->timers, new_size * sizeof(timer_context_t)); if (!new_timers) { common_mutex_unlock(reactor->mutex); return -1; } reactor->timers = new_timers; reactor->timer_size = new_size; } /* 创建定时器fd */ int timer_fd = create_timer_fd(interval_ms); if (timer_fd < 0) { common_mutex_unlock(reactor->mutex); return -1; } /* 添加到Reactor */ int timer_id = reactor->next_timer_id++; reactor->timers[reactor->timer_count].callback = callback; reactor->timers[reactor->timer_count].user_data = user_data; reactor->timers[reactor->timer_count].interval_ms = interval_ms; reactor->timers[reactor->timer_count].repeat = repeat; reactor->timers[reactor->timer_count].timer_fd = timer_fd; /* 添加读事件监视 */ if (reactor_add(reactor, timer_fd, REACTOR_EVENT_READ, NULL, (void*)(intptr_t)timer_id) < 0) { close(timer_fd); common_mutex_unlock(reactor->mutex); return -1; } reactor->timer_count++; common_mutex_unlock(reactor->mutex); LOG_DEBUG("REACTOR", "Added timer id=%d, interval=%dms, repeat=%s", timer_id, interval_ms, repeat ? "yes" : "no"); return timer_id; } ​ /** * @brief 删除定时器 */ int reactor_remove_timer(reactor_t reactor, int timer_id) { if (!reactor || timer_id < 0 || timer_id >= reactor->timer_count) { errno = EINVAL; return -1; } common_mutex_lock(reactor->mutex); /* 从Reactor删除 */ if (reactor_remove(reactor, reactor->timers[timer_id].timer_fd) < 0) { common_mutex_unlock(reactor->mutex); return -1; } /* 关闭定时器fd */ close(reactor->timers[timer_id].timer_fd); /* 从数组删除(移动最后一个元素到当前位置) */ if (timer_id < reactor->timer_count - 1) { reactor->timers[timer_id] = reactor->timers[reactor->timer_count - 1]; } reactor->timer_count--; common_mutex_unlock(reactor->mutex); LOG_DEBUG("REACTOR", "Removed timer id=%d", timer_id); return 0; } ​ /** * @brief 检查fd是否在Reactor中 */ bool reactor_contains(reactor_t reactor, int fd) { if (!reactor || fd < 0 || fd >= reactor->context_size) { return false; } common_mutex_lock(reactor->mutex); bool result = reactor->contexts[fd].active; common_mutex_unlock(reactor->mutex); return result; } ​ /** * @brief 获取Reactor中监视的fd数量 */ int reactor_count(reactor_t reactor) { if (!reactor) { return 0; } common_mutex_lock(reactor->mutex); int count = reactor->context_count; common_mutex_unlock(reactor->mutex); return count; } ​ /** * @brief 设置用户数据 */ int reactor_set_userdata(reactor_t reactor, int fd, void* user_data) { if (!reactor || fd < 0 || fd >= reactor->context_size) { errno = EINVAL; return -1; } common_mutex_lock(reactor->mutex); if (!reactor->contexts[fd].active) { common_mutex_unlock(reactor->mutex); errno = ENOENT; return -1; } reactor->contexts[fd].user_data = user_data; common_mutex_unlock(reactor->mutex); return 0; } ​ /** * @brief 获取用户数据 */ void* reactor_get_userdata(reactor_t reactor, int fd) { if (!reactor || fd < 0 || fd >= reactor->context_size) { return NULL; } common_mutex_lock(reactor->mutex); if (!reactor->contexts[fd].active) { common_mutex_unlock(reactor->mutex); return NULL; } void* user_data = reactor->contexts[fd].user_data; common_mutex_unlock(reactor->mutex); return user_data; }

第三部分:Reactor服务器示例

3.1 Reactor Echo服务器示例 (examples/reactor_echo.c)

/** * @file reactor_echo.c * @brief Reactor模式Echo服务器示例 * * 演示如何使用Reactor框架构建高性能事件驱动服务器。 * 单线程处理多个客户端连接。 * * @version 1.0 * @date 2024-01-01 */ ​ #include "socket.h" #include "reactor.h" #include <stdio.h> #include <string.h> #include <stdlib.h> #include <signal.h> #include <errno.h> ​ /* ==================== 连接上下文 ==================== */ ​ /** * @brief 客户端连接上下文 */ typedef struct { socket_t sock; /**< Socket句柄 */ char buffer[1024]; /**< 接收缓冲区 */ size_t buffer_len; /**< 缓冲区数据长度 */ size_t total_received; /**< 总共接收的字节数 */ size_t total_sent; /**< 总共发送的字节数 */ } client_context_t; ​ /** * @brief 服务器上下文 */ typedef struct { reactor_t reactor; /**< Reactor实例 */ socket_t server_sock; /**< 服务器Socket */ int client_count; /**< 当前客户端数量 */ bool running; /**< 运行标志 */ } server_context_t; ​ /* ==================== 事件处理函数 ==================== */ ​ /** * @brief 处理客户端数据 * * @param client_ctx 客户端上下文 */ static void handle_client_data(client_context_t* client_ctx) { /* 回显数据 */ if (sock_send(client_ctx->sock, client_ctx->buffer, client_ctx->buffer_len, 1000) > 0) { client_ctx->total_sent += client_ctx->buffer_len; } /* 清空缓冲区 */ client_ctx->buffer_len = 0; } ​ /** * @brief 客户端读事件回调 * * @param reactor Reactor实例 * @param fd 文件描述符 * @param events 事件类型 * @param user_data 用户数据(客户端上下文) */ static void on_client_read(reactor_t reactor, int fd, reactor_event_t events, void* user_data) { client_context_t* ctx = (client_context_t*)user_data; if (events & REACTOR_EVENT_ERROR || events & REACTOR_EVENT_HUP) { /* 连接错误或关闭 */ printf("Client fd=%d disconnected\n", fd); /* 从Reactor删除 */ reactor_remove(reactor, fd); /* 关闭Socket */ sock_close(ctx->sock); /* 释放上下文 */ common_free(ctx); /* 更新服务器上下文中的客户端计数 */ server_context_t* server_ctx = reactor_get_userdata(reactor, 0); if (server_ctx) { server_ctx->client_count--; printf("Client count: %d\n", server_ctx->client_count); } return; } if (events & REACTOR_EVENT_READ) { /* 接收数据 */ ssize_t n = sock_recv(ctx->sock, ctx->buffer + ctx->buffer_len, sizeof(ctx->buffer) - ctx->buffer_len - 1, 0); if (n > 0) { ctx->buffer_len += n; ctx->total_received += n; /* 确保字符串以NULL结尾(用于打印) */ ctx->buffer[ctx->buffer_len] = '\0'; printf("Received %zd bytes from fd=%d: %s\n", n, fd, ctx->buffer); /* 处理数据 */ handle_client_data(ctx); } else if (n == 0) { /* 连接关闭 */ printf("Client fd=%d closed connection\n", fd); reactor_remove(reactor, fd); sock_close(ctx->sock); common_free(ctx); } } } ​ /** * @brief 服务器接受连接回调 * * @param reactor Reactor实例 * @param fd 文件描述符(服务器Socket) * @param events 事件类型 * @param user_data 用户数据(服务器上下文) */ static void on_server_accept(reactor_t reactor, int fd, reactor_event_t events, void* user_data) { server_context_t* server_ctx = (server_context_t*)user_data; if (events & REACTOR_EVENT_READ) { /* 接受新连接 */ socket_t client_sock = sock_accept(server_ctx->server_sock, NULL, 0); if (client_sock == SOCKET_INVALID) { if (errno != EAGAIN && errno != EWOULDBLOCK) { LOG_ERROR("Accept failed: %s", sock_strerror(errno)); } return; } /* 设置非阻塞 */ sock_set_nonblock(client_sock, true); /* 创建客户端上下文 */ client_context_t* client_ctx = common_calloc(1, sizeof(client_context_t)); if (!client_ctx) { LOG_ERROR("Failed to allocate client context"); sock_close(client_sock); return; } client_ctx->sock = client_sock; /* 添加到Reactor监视读事件 */ if (reactor_add(reactor, client_sock, REACTOR_EVENT_READ, on_client_read, client_ctx) < 0) { LOG_ERROR("Failed to add client to reactor"); common_free(client_ctx); sock_close(client_sock); return; } server_ctx->client_count++; printf("New client connected fd=%d, total clients: %d\n", client_sock, server_ctx->client_count); } } ​ /** * @brief 定时器回调(统计输出) * * @param reactor Reactor实例 * @param timer_id 定时器ID * @param user_data 用户数据(服务器上下文) */ static void on_stats_timer(reactor_t reactor, int timer_id, void* user_data) { server_context_t* server_ctx = (server_context_t*)user_data; printf("=== Server Stats ===\n"); printf("Running: %s\n", server_ctx->running ? "yes" : "no"); printf("Clients: %d\n", server_ctx->client_count); printf("Reactor event count: %d\n", reactor_count(reactor)); printf("====================\n"); } ​ /** * @brief 信号处理函数 * * @param sig 信号编号 */ static void signal_handler(int sig) { printf("\nReceived signal %d, shutting down...\n", sig); } ​ /** * @brief 初始化服务器 * * @param port 监听端口 * @param server_ctx 输出服务器上下文 * @return int 0成功,-1失败 */ static int init_server(uint16_t port, server_context_t* server_ctx) { /* 创建服务器Socket */ socket_t server_sock = sock_create(SOCK_AF_INET, SOCK_TYPE_STREAM); if (server_sock == SOCKET_INVALID) { fprintf(stderr, "Failed to create server socket: %s\n", sock_strerror(errno)); return -1; } /* 设置Socket选项 */ sock_set_reuseaddr(server_sock, true); sock_set_reuseport(server_sock, true); sock_set_nonblock(server_sock, true); /* 绑定地址 */ sock_addr_t addr; if (sock_addr_ipv4("0.0.0.0", port, &addr) < 0) { fprintf(stderr, "Failed to create address\n"); sock_close(server_sock); return -1; } if (sock_bind(server_sock, &addr) < 0) { fprintf(stderr, "Failed to bind: %s\n", sock_strerror(errno)); sock_close(server_sock); return -1; } /* 开始监听 */ if (sock_listen(server_sock, 128) < 0) { fprintf(stderr, "Failed to listen: %s\n", sock_strerror(errno)); sock_close(server_sock); return -1; } /* 创建Reactor */ reactor_t reactor = reactor_create(1024, REACTOR_TRIGGER_LEVEL); if (!reactor) { fprintf(stderr, "Failed to create reactor\n"); sock_close(server_sock); return -1; } /* 初始化服务器上下文 */ memset(server_ctx, 0, sizeof(*server_ctx)); server_ctx->reactor = reactor; server_ctx->server_sock = server_sock; server_ctx->client_count = 0; server_ctx->running = true; /* 将服务器上下文存储到Reactor(fd=0保留给服务器) */ reactor_set_userdata(reactor, 0, server_ctx); /* 添加服务器Socket到Reactor */ if (reactor_add(reactor, server_sock, REACTOR_EVENT_READ, on_server_accept, server_ctx) < 0) { fprintf(stderr, "Failed to add server to reactor\n"); reactor_destroy(reactor); sock_close(server_sock); return -1; } /* 添加统计定时器(每秒触发) */ reactor_add_timer(reactor, 1000, on_stats_timer, server_ctx, true); printf("Server initialized on port %d\n", port); printf("Press Ctrl+C to stop\n"); return 0; } ​ /** * @brief 清理服务器 * * @param server_ctx 服务器上下文 */ static void cleanup_server(server_context_t* server_ctx) { if (!server_ctx) { return; } printf("Cleaning up server...\n"); server_ctx->running = false; /* 关闭服务器Socket */ if (server_ctx->server_sock != SOCKET_INVALID) { sock_close(server_ctx->server_sock); server_ctx->server_sock = SOCKET_INVALID; } /* 销毁Reactor */ if (server_ctx->reactor) { reactor_destroy(server_ctx->reactor); server_ctx->reactor = NULL; } printf("Server cleanup completed\n"); } ​ /** * @brief 主函数 */ int main(int argc, char* argv[]) { uint16_t port = 8080; /* 解析命令行参数 */ if (argc > 1) { int p = atoi(argv[1]); if (p > 0 && p <= 65535) { port = (uint16_t)p; } } /* 设置信号处理 */ signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); /* 初始化服务器 */ server_context_t server_ctx; if (init_server(port, &server_ctx) < 0) { return 1; } /* 运行Reactor事件循环 */ printf("Starting reactor event loop...\n"); while (server_ctx.running) { int ret = reactor_run(server_ctx.reactor, 1000); if (ret < 0 && errno != EINTR) { LOG_ERROR("Reactor run failed: %s", sock_strerror(errno)); break; } } /* 清理 */ cleanup_server(&server_ctx); printf("Server stopped\n"); return 0; }

3.2 Reactor与基础Socket集成示例 (examples/reactor_udp.c)

/** * @file reactor_udp.c * @brief Reactor UDP服务器示例 * * 演示如何使用Reactor处理UDP Socket。 * * @version 1.0 * @date 2024-01-01 */ ​ #include "socket.h" #include "reactor.h" #include <stdio.h> #include <string.h> #include <stdlib.h> #include <signal.h> ​ /* UDP服务器上下文 */ typedef struct { reactor_t reactor; socket_t udp_sock; int packet_count; size_t total_bytes; bool running; } udp_server_t; ​ /** * @brief UDP数据接收回调 */ static void on_udp_data(reactor_t reactor, int fd, reactor_event_t events, void* user_data) { udp_server_t* server = (udp_server_t*)user_data; if (events & REACTOR_EVENT_READ) { char buffer[4096]; sock_addr_t src_addr; /* 接收UDP数据 */ ssize_t n = sock_recvfrom(server->udp_sock, buffer, sizeof(buffer), &src_addr, 0); if (n > 0) { server->packet_count++; server->total_bytes += n; /* 打印接收信息 */ char addr_str[256]; sock_addr_str(&src_addr, addr_str, sizeof(addr_str)); printf("UDP packet #%d from %s: %zd bytes\n", server->packet_count, addr_str, n); /* 回显数据 */ sock_sendto(server->udp_sock, buffer, n, &src_addr); } } } ​ /** * @brief 统计定时器回调 */ static void on_udp_stats(reactor_t reactor, int timer_id, void* user_data) { udp_server_t* server = (udp_server_t*)user_data; printf("=== UDP Server Stats ===\n"); printf("Packets received: %d\n", server->packet_count); printf("Total bytes: %zu\n", server->total_bytes); printf("=======================\n"); } ​ int main(int argc, char* argv[]) { uint16_t port = 9090; if (argc > 1) { port = (uint16_t)atoi(argv[1]); } /* 创建UDP Socket */ socket_t udp_sock = sock_create(SOCK_AF_INET, SOCK_TYPE_DGRAM); if (udp_sock == SOCKET_INVALID) { fprintf(stderr, "Failed to create UDP socket\n"); return 1; } /* 绑定地址 */ sock_addr_t addr; sock_addr_ipv4("0.0.0.0", port, &addr); if (sock_bind(udp_sock, &addr) < 0) { fprintf(stderr, "Failed to bind UDP socket\n"); sock_close(udp_sock); return 1; } /* 设置非阻塞 */ sock_set_nonblock(udp_sock, true); /* 创建Reactor */ reactor_t reactor = reactor_create(1024, REACTOR_TRIGGER_LEVEL); if (!reactor) { fprintf(stderr, "Failed to create reactor\n"); sock_close(udp_sock); return 1; } /* 初始化服务器上下文 */ udp_server_t server = { .reactor = reactor, .udp_sock = udp_sock, .packet_count = 0, .total_bytes = 0, .running = true }; /* 添加UDP Socket到Reactor */ if (reactor_add(reactor, udp_sock, REACTOR_EVENT_READ, on_udp_data, &server) < 0) { fprintf(stderr, "Failed to add UDP socket to reactor\n"); reactor_destroy(reactor); sock_close(udp_sock); return 1; } /* 添加统计定时器 */ reactor_add_timer(reactor, 5000, on_udp_stats, &server, true); printf("UDP server started on port %d\n", port); printf("Press Ctrl+C to stop\n"); /* 运行Reactor */ while (server.running) { int ret = reactor_run(reactor, 1000); if (ret < 0 && errno != EINTR) { break; } } /* 清理 */ reactor_destroy(reactor); sock_close(udp_sock); printf("UDP server stopped\n"); return 0; }

第四部分:高级Reactor特性

4.1 连接池管理 (src/connection_pool.c)

/** * @file connection_pool.c * @brief 连接池管理 * * 基于Reactor的连接池管理,支持连接复用和负载均衡。 * * @version 1.0 * @date 2024-01-01 */ ​ #include "reactor.h" #include "socket.h" #include <stdlib.h> #include <string.h> ​ /* ==================== 连接池定义 ==================== */ ​ /** * @brief 连接状态 */ typedef enum { CONN_STATE_IDLE, /**< 空闲 */ CONN_STATE_CONNECTING, /**< 连接中 */ CONN_STATE_READY, /**< 就绪 */ CONN_STATE_BUSY, /**< 忙碌 */ CONN_STATE_ERROR /**< 错误 */ } conn_state_t; ​ /** * @brief 连接项 */ typedef struct { socket_t sock; /**< Socket句柄 */ sock_addr_t addr; /**< 远程地址 */ conn_state_t state; /**< 连接状态 */ uint64_t last_used; /**< 最后使用时间 */ uint64_t created; /**< 创建时间 */ uint32_t use_count; /**< 使用次数 */ void* user_data; /**< 用户数据 */ } connection_t; ​ /** * @brief 连接池 */ typedef struct { reactor_t reactor; /**< Reactor实例 */ connection_t* connections; /**< 连接数组 */ int capacity; /**< 容量 */ int count; /**< 当前数量 */ int max_idle_time; /**< 最大空闲时间(秒) */ common_mutex_t mutex; /**< 互斥锁 */ } connection_pool_t; ​ /* ==================== 连接池API ==================== */ ​ /** * @brief 创建连接池 * * @param capacity 容量 * @param max_idle_time 最大空闲时间(秒) * @return connection_pool_t* 连接池,NULL失败 */ connection_pool_t* connpool_create(int capacity, int max_idle_time) { connection_pool_t* pool = common_calloc(1, sizeof(connection_pool_t)); if (!pool) { return NULL; } pool->connections = common_calloc(capacity, sizeof(connection_t)); if (!pool->connections) { common_free(pool); return NULL; } pool->reactor = reactor_create(1024, REACTOR_TRIGGER_LEVEL); if (!pool->reactor) { common_free(pool->connections); common_free(pool); return NULL; } pool->capacity = capacity; pool->count = 0; pool->max_idle_time = max_idle_time; pool->mutex = common_mutex_create(); if (!pool->mutex) { reactor_destroy(pool->reactor); common_free(pool->connections); common_free(pool); return NULL; } LOG_DEBUG("CONNPOOL", "Connection pool created: capacity=%d", capacity); return pool; } ​ /** * @brief 销毁连接池 * * @param pool 连接池 */ void connpool_destroy(connection_pool_t* pool) { if (!pool) { return; } common_mutex_lock(pool->mutex); /* 关闭所有连接 */ for (int i = 0; i < pool->count; i++) { if (pool->connections[i].sock != SOCKET_INVALID) { sock_close(pool->connections[i].sock); } } common_mutex_unlock(pool->mutex); /* 销毁Reactor */ if (pool->reactor) { reactor_destroy(pool->reactor); } /* 销毁互斥锁 */ if (pool->mutex) { common_mutex_destroy(pool->mutex); } /* 释放内存 */ common_free(pool->connections); common_free(pool); LOG_DEBUG("CONNPOOL", "Connection pool destroyed"); } ​ /** * @brief 从连接池获取连接 * * @param pool 连接池 * @param addr 远程地址 * @param timeout_ms 超时时间 * @return connection_t* 连接,NULL失败 */ connection_t* connpool_acquire(connection_pool_t* pool, const sock_addr_t* addr, int timeout_ms) { if (!pool || !addr) { return NULL; } common_mutex_lock(pool->mutex); /* 查找空闲连接 */ connection_t* conn = NULL; for (int i = 0; i < pool->count; i++) { if (pool->connections[i].state == CONN_STATE_IDLE && sock_addr_equal(&pool->connections[i].addr, addr)) { conn = &pool->connections[i]; break; } } if (conn) { /* 找到空闲连接 */ conn->state = CONN_STATE_BUSY; conn->last_used = time(NULL); conn->use_count++; common_mutex_unlock(pool->mutex); LOG_DEBUG("CONNPOOL", "Acquired existing connection to %s", addr_to_str(addr)); return conn; } /* 没有空闲连接,检查是否可以创建新连接 */ if (pool->count < pool->capacity) { conn = &pool->connections[pool->count]; /* 创建新连接 */ conn->sock = sock_create(SOCK_AF_INET, SOCK_TYPE_STREAM); if (conn->sock == SOCKET_INVALID) { common_mutex_unlock(pool->mutex); return NULL; } /* 设置非阻塞 */ sock_set_nonblock(conn->sock, true); /* 连接远程 */ if (sock_connect(conn->sock, addr, timeout_ms) < 0) { if (errno != EINPROGRESS) { sock_close(conn->sock); common_mutex_unlock(pool->mutex); return NULL; } /* 异步连接中 */ conn->state = CONN_STATE_CONNECTING; } else { /* 同步连接成功 */ conn->state = CONN_STATE_READY; } /* 复制地址 */ sock_addr_copy(&conn->addr, addr); conn->created = time(NULL); conn->last_used = conn->created; conn->use_count = 1; pool->count++; /* 添加到Reactor监视写事件(用于检测连接完成) */ if (conn->state == CONN_STATE_CONNECTING) { reactor_add(pool->reactor, conn->sock, REACTOR_EVENT_WRITE, NULL, conn); } common_mutex_unlock(pool->mutex); LOG_DEBUG("CONNPOOL", "Created new connection to %s", addr_to_str(addr)); return conn; } /* 连接池已满 */ common_mutex_unlock(pool->mutex); LOG_WARN("CONNPOOL", "Connection pool full"); return NULL; } ​ /** * @brief 释放连接回连接池 * * @param pool 连接池 * @param conn 连接 */ void connpool_release(connection_pool_t* pool, connection_t* conn) { if (!pool || !conn) { return; } common_mutex_lock(pool->mutex); /* 检查连接状态 */ if (conn->state == CONN_STATE_ERROR) { /* 错误连接,关闭并从池中移除 */ sock_close(conn->sock); /* 将最后一个连接移到当前位置 */ if (conn != &pool->connections[pool->count - 1]) { *conn = pool->connections[pool->count - 1]; } pool->count--; LOG_DEBUG("CONNPOOL", "Removed error connection"); } else { /* 正常连接,标记为空闲 */ conn->state = CONN_STATE_IDLE; conn->last_used = time(NULL); LOG_DEBUG("CONNPOOL", "Released connection back to pool"); } common_mutex_unlock(pool->mutex); } ​ /** * @brief 运行连接池维护任务 * * @param pool 连接池 */ void connpool_maintain(connection_pool_t* pool) { if (!pool) { return; } common_mutex_lock(pool->mutex); uint64_t now = time(NULL); /* 清理空闲时间过长的连接 */ for (int i = pool->count - 1; i >= 0; i--) { connection_t* conn = &pool->connections[i]; if (conn->state == CONN_STATE_IDLE && now - conn->last_used > pool->max_idle_time) { LOG_DEBUG("CONNPOOL", "Closing idle connection (idle for %ld seconds)", now - conn->last_used); sock_close(conn->sock); /* 将最后一个连接移到当前位置 */ if (i < pool->count - 1) { pool->connections[i] = pool->connections[pool->count - 1]; } pool->count--; } } common_mutex_unlock(pool->mutex); /* 运行Reactor处理异步连接事件 */ reactor_run(pool->reactor, 0); } ​ /** * @brief 连接池统计 * * @param pool 连接池 * @param total 输出总数 * @param idle 输出空闲数 * @param busy 输出忙碌数 * @param errors 输出错误数 */ void connpool_stats(connection_pool_t* pool, int* total, int* idle, int* busy, int* errors) { if (!pool) { return; } common_mutex_lock(pool->mutex); if (total) *total = pool->count; if (idle) *idle = 0; if (busy) *busy = 0; if (errors) *errors = 0; for (int i = 0; i < pool->count; i++) { switch (pool->connections[i].state) { case CONN_STATE_IDLE: if (idle) (*idle)++; break; case CONN_STATE_BUSY: if (busy) (*busy)++; break; case CONN_STATE_ERROR: if (errors) (*errors)++; break; default: break; } } common_mutex_unlock(pool->mutex); }

第五部分:完整设计总结

5.1 模块关系图

┌─────────────────┐ │ Application │ └────────┬────────┘ │ ┌────────▼────────┐ │ Reactor │ ← 事件驱动核心 │ (reactor.h) │ └────────┬────────┘ │ ┌────────▼────────┐ │ Socket │ ← 基础通信层 │ (socket.h) │ └────────┬────────┘ │ ┌────────▼────────┐ │ Common Lib │ ← 基础设施 │ (common.h) │ └─────────────────┘

5.2 设计原则体现

1.高内聚
  • reactor.c: 只负责事件驱动逻辑

  • socket_*.c: 只负责基础通信

  • connection_pool.c: 只负责连接管理

2.低耦合
  • Reactor不依赖具体协议

  • Socket不依赖事件模型

  • 通过回调函数解耦

3.单一职责
  • 每个文件一个主要功能

  • 每个函数一个明确任务

  • 每个模块一个清晰接口

5.3 性能考虑

1.事件处理优化
// 水平触发 vs 边沿触发 reactor_create(1024, REACTOR_TRIGGER_EDGE); // 高性能 reactor_create(1024, REACTOR_TRIGGER_LEVEL); // 兼容性好
2.内存管理
// 预分配避免频繁分配 reactor->contexts = common_calloc(reactor->context_size, sizeof(event_context_t));
3.锁优化
// 细粒度锁,减少竞争 common_mutex_lock(reactor->mutex); // 只有修改共享数据时才加锁 common_mutex_unlock(reactor->mutex);

5.4 使用建议

1.小规模应用:直接使用Socket模块
// 简单客户端/服务器 socket_t sock = sock_create(...); sock_connect(sock, ...);
2.中等规模:使用Reactor
// 事件驱动服务器 reactor_t reactor = reactor_create(...); reactor_add(reactor, server_sock, REACTOR_EVENT_READ, on_accept, NULL); reactor_run(reactor, -1);
3.大规模应用:连接池 + Reactor
// 高并发服务器 connection_pool_t* pool = connpool_create(100, 300); connection_t* conn = connpool_acquire(pool, addr, 5000);

5.5 扩展性

1.支持更多事件源
// 可以扩展支持: // - 信号事件 // - 文件事件 // - 进程事件 // - 定时器事件(已实现)
2.多Reactor模式
// 主从Reactor模式 reactor_t main_reactor; // 只处理accept reactor_t sub_reactors[4]; // 处理IO,每个线程一个
3.协议支持
// 可以基于此框架实现: // - HTTP服务器 // - WebSocket服务器 // - Redis协议 // - MQTT代理

总结

这个Socket + Reactor组合提供了:

基础层(socket_*.c)

  • 简单直接的Socket API

  • 完整的错误处理

  • 跨平台准备

事件驱动层(reactor.c)

  • 高性能epoll封装

  • 定时器支持

  • 线程安全

应用层(connection_pool.c, 示例)

  • 连接池管理

  • 负载均衡

  • 资源复用

关键优势

  1. 从简单到复杂:可以按需使用不同层级

  2. 性能优秀:接近原生epoll性能

  3. 易于使用:清晰的API设计

  4. 易于扩展:模块化设计

  5. 生产就绪:包含错误处理、日志、统计

这个设计既提供了学习的清晰性(可以理解每一层实现),又提供了生产的实用性(可以直接用于实际项目)。可以根据具体需求选择使用层级:需要快速原型就用Socket层,需要高性能就用Reactor层。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 12:29:36

PlantUML在线编辑器:基于代码的UML建模解决方案深度解析

PlantUML在线编辑器&#xff1a;基于代码的UML建模解决方案深度解析 【免费下载链接】plantuml-editor PlantUML online demo client 项目地址: https://gitcode.com/gh_mirrors/pl/plantuml-editor PlantUML在线编辑器提供了一种革命性的UML建模方式&#xff0c;通过简…

作者头像 李华
网站建设 2026/4/17 18:05:25

《从零开始构建智能体》—— 实践与理论结合的智能体入门指南

《从零开始构建智能体》—— 实践与理论结合的智能体入门指南 项目介绍 在2024年&#xff0c;"百模大战"即将拉开序幕&#xff0c;而2025年则标志着"Agent 元年"的到来。随着技术的不断发展&#xff0c;构建更智能的智能体应用将成为新的焦点。然而&…

作者头像 李华
网站建设 2026/3/31 18:45:40

FP8量化技术解析:Stable Diffusion 3.5为何能兼顾速度与画质

FP8量化技术解析&#xff1a;Stable Diffusion 3.5为何能兼顾速度与画质 在生成式AI的浪潮中&#xff0c;Stable Diffusion系列模型已经从研究原型演变为工业级内容生成的核心引擎。然而&#xff0c;随着模型能力不断增强&#xff0c;其对显存和计算资源的需求也呈指数级增长—…

作者头像 李华
网站建设 2026/4/18 5:01:46

PyTorch安装教程GPU加速篇:基于CUDA 12.1的最新实践

PyTorch安装教程GPU加速篇&#xff1a;基于CUDA 12.1的最新实践 在深度学习领域&#xff0c;算力就是生产力。随着大模型时代的到来&#xff0c;动辄数十亿参数的神经网络让传统CPU训练变得遥不可及——一次完整训练可能需要数周甚至更久。而一块RTX 4090&#xff0c;在正确配…

作者头像 李华
网站建设 2026/4/17 19:38:15

STL_unordered_map

它是现代C编程中使用最频繁、性能最高的容器之一&#xff0c;理解其工作原理至关重要。1. 核心概念&#xff1a;什么是 unordered_map&#xff1f;std::unordered_map 是一个无序的关联式容器&#xff0c;存储的是键值对。它的核心特性与 std::set 形成鲜明对比&#xff1a;键的…

作者头像 李华
网站建设 2026/4/18 3:42:37

Matlab【独家原创】基于IVY-CNN-LSTM-Attention-SHAP可解释性分析的分类预测

目录 1、代码简介 2、代码运行结果展示 3、代码获取 1、代码简介 (IVY-CNN-LSTM-AttentionSHAP)基于常青藤算法优化卷积神经网络结合长短期记忆神经网络结合注意力机制的数据多输入单输出SHAP可解释性分析的分类预测模型 由于IVY-CNN-LSTM-Attention在使用SHAP分析时速度较…

作者头像 李华