TinyWebServer源码解析——Reactor和Proactor双模式web组件

TinyWebServer源码解析——Reactor和Proactor双模式web组件

项目地址
https://github.com/qinguoyi/TinyWebServer.git
尊重开源精神,保障作者权益,内容均为原创,如有雷同,纯属巧合

本文件是将TinyWebSever其他组件串联起来的文件,笔者水平有限,仅能挖出这些技术栈,以供讨论,仅个人观点,如有错误,还望海涵!

定义了一个WebServer类

通过整个服务器程序的主控逻辑与核心调度模块,实现了一个高性能、可配置、支持 Reactor/Proactor 双模式的微型 Web 服务器


封装内容:
  1. 构造函数初始化所有成员为安全初值
  2. 析构函数释放所有动态资源
  3. void init()函数接收用户配置参数
  4. void trig_mode()函数设置epoll触发模式
  5. void log_write()函数初始化日志系统
  6. void sql_pool()函数创建MYSQL连接池
  7. void thread_pool()函数创建线程池,后续HTTP请求对象提交给线程池异步处理
  8. void eventListen()函数完成网络监听准备
  9. void eventLoop()函数主事件循环
  10. bool dealclientdata()函数处理新客户端连接
  11. bool dealwithsignal()函数从信号管道读取信号
  12. void dealwithread()函数处理可读事件
  13. void dealwithwrite()函数处理可写事件
  14. void timer()函数为新连接创建定时器

核心函数:
voidinit(int port , string user, string passWord, string databaseName,int log_write ,int opt_linger,int trigmode,int sql_num,int thread_num,int close_log,int actor_model);
  1. init()函数初始化端口,数据库,日志,触发模式,线程数,其否启用Reactor模式
    • void trig_mode()设置listenfd和connfd的epoll触发模式
    • log_write()初始化日志系统(单例 Log)
    • sql_pool():创建 MySQL 连接池,并初始化用户表缓存
    • thread_pool()创建 threadpool<http_conn>,用于异步处理请求
    • eventListen()创建监听 socket、epoll、信号管道、设置信号处理
  2. void eventLoop()网络事件循环,基于epoll_wait实现高性能I/O多路复用
事件类型处理函数说明
新连接 (m_listenfd)dealclientdata()接受新客户端,初始化 http_conn 和定时器
信号通知 (m_pipefd[0])dealwithsignal()处理 SIGALRM(定时)和 SIGTERM(退出)
可读事件 (EPOLLIN)dealwithread()读取 HTTP 请求
可写事件 (EPOLLOUT)dealwithwrite()发送 HTTP 响应
  1. m_actormodel模式处理
    • m_actormode == 0 时(Proactor模式)
      • 主线程完成完整I/O操作
      • 将已读取/待发送的http_conn对象放入线程池,仅执行process()
    • m_actormode == 1 时(Reactor模式)
      • 主线程只负责事件通知
      • 线程池的工作线程执行实际I/O+process
  2. 定时器管理:
    • 使用基于链表的定时器
    • 每个新连接创建一个定时器
    • 每次读写成功则adjust_timer()延长超时时间
    • 超时或出错就调用deal_timer()
类别函数功能
生命周期构造 / 析构资源初始化与释放
初始化init, trig_mode, log_write, sql_pool, thread_pool, eventListen配置与启动准备
主循环eventLoop驱动整个服务器运行
事件处理dealclientdata, dealwithsignal, dealwithread, dealwithwrite响应 epoll 事件
定时器timer为连接设置超时
工具addfd, modfd, show_error辅助 I/O 与错误处理

触发模式:
  1. LT(水平触发):epoll默认模式
    • 只要fd处于就绪状态就会持续通知
  2. ET(边缘触发):
    • 只当fd状态改变时,触发一次
    • 需配合非阻塞I/O+循环读写
    • 循环读写一般使用while循环,不用for循环是为了避免虚假唤醒
  3. 参数组合
// trigmode 参数决定组合: 0: LISTEN_LT + CONN_LT (最安全) 1: LISTEN_LT + CONN_ET (常用) 2: LISTEN_ET + CONN_LT 3: LISTEN_ET + CONN_ET (最高性能,但 listenfd 也需循环 accept) 

Reactor模式
    • 创建socket
    • 绑定地址与端口
    • 开始监听
    • epoll
  1. 事件处理
    • 当事件循环发现fd就绪后,执行相应的义务逻辑
    • 常见类型

事件循环

while(!stop_server){int n =epoll_wait(epollfd, events, MAX_EVENTS,-1);for(int i =0; i < n; i++){int fd = events[i].data.fd;if(fd == listenfd){// 处理新连接 }elseif(events[i].events & EPOLLIN){// 处理可读事件 }elseif(events[i].events & EPOLLOUT){// 处理可写事件 }}}

网络监听

int listenfd =socket(AF_INET, SOCK_STREAM,0);
bind(listenfd,(structsockaddr*)&addr,sizeof(addr));
listen(listenfd,5);// 5 是 backlog,等待队列长度
事件类型触发条件处理动作
新连接listenfd 可读调用 accept() 获取 connfd,初始化连接对象
可读事件(EPOLLIN)客户端发送了数据调用 read() 读取 HTTP 请求
可写事件(EPOLLOUT)socket 发送缓冲区有空位调用 write() 发送 HTTP 响应
错误/关闭对端关闭连接或出错清理资源,关闭 fd
    • 信号是异步的
    • 创建一个 socketpair 或 pipe(两个 fd,一端写,一端读)。
    • 注册读端到 epoll
    • 在信号处理函数中,只向写端写一个字节(如 '1')。
    • 主循环的 epoll_wait 会检测到读端可读,从而在主线程安全上下文中处理信号。
    • 将异步信号转换为同步I/O
  1. 可读事件和可写事件
    • 可读事件:
      • fd的接收缓冲区有数据可读
      • 调用read()或recv()读取数据
    • 可写事件:
      • fd的发送缓冲区由空闲空间,可以写入数据
      • 调用write()或send()发送数据

信号管道

// 初始化 socketpair(PF_UNIX, SOCK_STREAM,0, m_pipefd);// 信号处理函数voidaddsig(int sig,void(handler)(int)){structsigaction sa; sa.sa_handler = handler;sigaction(sig,&sa,NULL);}// SIGALRM 处理函数 voidalarm_handler(int sig){send(m_pipefd[1],"1",1,0);// 只写1字节! }// 主循环中 if(sockfd == m_pipefd[0]){dealwithsignal();// 安全地读取并处理信号 }

新连接

信号

connfd 可读

connfd 可写

yes

yes

启动服务器

创建 listenfd 并监听

创建 epoll + 信号管道

注册 listenfd 和 pipefd 到 epoll

进入 eventLoop

epoll_wait 返回事件?

dealclientdata: accept + 初始化 connfd

dealwithsignal: 读管道,设置 timeout/stop

dealwithread: 读 HTTP 请求

dealwithwrite: 发 HTTP 响应

将 connfd 加入 epoll 监听

提交任务到线程池处理请求

发送响应,若未发完则重注册 EPOLLOUT

生成响应内容

是否timeout

关闭超时连接

是否stop_server

退出循环,清理资源

Read more

【感恩支持】一票一星皆厚意,一行一履总关情——Java与PostgreSQL正在Commit这份支持,永不Rollback

【感恩支持】一票一星皆厚意,一行一履总关情——Java与PostgreSQL正在Commit这份支持,永不Rollback

目录 前言 1、回味硝烟 2、感恩助力 3、铭记助力 一、该怎么存储呢 1、PG数据库的设计与实现 2、JAVA后台设计与实现 二、JAVA数据存储实践 1、持久化所有助力 2、助力数据查询 三、助力可视化 1、助力名单展示 2、时空引力分析 四、总结 前言 1、回味硝烟         当时间拨回2026年1月24日零点,2025ZEEKLOG博客之星评选网络投票的硝烟终于在零点投票通道关闭的那一刻缓缓散去。回望这场持续了7天的技术圈"全民公投",恍若一场漫长而激烈的数据库高并发事务——每一位参赛者的票数曲线在屏幕上疯狂跳动,每一次刷新都可能意味着排名的重新排序。这是一场没有硝烟的战争,却充满了计算与决策的张力:有人选择在高并发的高峰期持续拉票,如同优化SQL查询般精准投放;有人在最后时刻发起"秒杀式"冲刺,像极了处理分布式事务时的最后提交。

By Ne0inhk
FARS全自动科研系统技术深度解析:从多智能体架构到工业化科研范式

FARS全自动科研系统技术深度解析:从多智能体架构到工业化科研范式

前言 2026年2月12日至2月22日,一场持续228小时33分钟的直播在全球AI社区引发了持续震荡。屏幕另一端,一个名为FARS(Fully Automated Research System)的全自动研究系统,在没有人类干预的情况下,自主完成了从文献调研到论文撰写的完整科研流程,最终产出100篇学术论文,总消耗114亿Token,成本10.4万美元。 这场实验的意义远不止于“AI写论文”的简单升级。它向世界展示了科学发现的根本范式正在发生转移——从依赖人类灵感的“手工作坊”,转向由AI驱动的“工业化流水线”。本文将从最底层的技术细节出发,逐层拆解FARS的系统架构、智能体协作机制、资源调度策略、成本控制模型,以及与竞品的技术对比,为读者呈现一个完整的全自动科研系统技术图谱。 第一章 系统总体架构:四智能体流水线设计 1.1 核心设计理念:研究系统的第一性原理 FARS的设计并非简单地模仿人类科研流程,而是基于团队对“研究系统”本质的重新思考。创始团队提出,一个理想的研究系统应遵循两条基本原则: 1. 高效拓展知识边界:系统的吞吐量应成为核心评估指标,而非单篇论文的完

By Ne0inhk
基于神经网络的学生学习情况分析系统-hadoop+django

基于神经网络的学生学习情况分析系统-hadoop+django

1. 开发语言:Python 2. 框架:django 3. Python版本:python3.8 4. 数据库:mysql 5.7 5. 数据库工具:Navicat12 6. 开发软件:PyCharm 系统展示 管理员登录 管理员功能界面 用户管理 学习数据 期末成绩预测 看板展示 摘要 系统基于B/S开发模式,采用Python语言进行开发,借助Django框架搭建系统架构,保证了系统的稳定性和可扩展性。同时,运用长短期记忆网络(LSTM)算法,对学生学习数据进行深入分析和挖掘。系统功能多样,管理员能够对用户信息进行全面管理,包括用户的注册、登录和权限设置等。可以对学生的学习数据进行收集、整理和分析,涵盖课堂表现、作业完成情况等。并且能够通过LSTM模型对学生的期末成绩进行科学预测,为教学决策提供有力支持。该系统的应用,

By Ne0inhk
【MySQL】三大范式

【MySQL】三大范式

下面我们来聊聊表的设计,如何设计一张比较合理,冗余性低且IO次数比较少,效率高的表。 我们需要先认识一下范式 什么是范式? 范式是⼀组规则。在设计关系数据库时,遵从不同的规范要求,设计出合理的关系型数据库,这些不同的规范要求被称为不同的范式。 范式有哪些? 关系数据库有六种范式:第⼀范式(1NF)、第⼆范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,⼜称完美范式),越高的范式数据库冗余越小。然而,普遍认为范式越高虽然对数据关系有更好的约束性,但也可能导致数据库IO更繁忙,因此在实际应用中,数据库设计通常只需满足第三范式即可,如果在想提高效率,再去增加某个字段的冗余性 为啥越高的范式数据库冗余越小,IO效率越忙呢?继续看 第一范式 第一范式即:数据库表的每⼀列都是不可分割的原子数据项,而不能是集合,数组,对象等非原子数据 在关系型数据库的设计中,满足第⼀范式是对关系模式的基本要求。

By Ne0inhk