第三周 Reactor 网络库与高并发服务器优化
网络库与高并发服务器优化前言项目简介环境与编译核心代码Ⅰ.BufferⅡ.ChannelⅢ.EventLoopⅣ.TimerⅤ.TcpConnection遇到的问题与积累导出导入前言本项目是基于 Linux epoll 实现的简易 Reactor 高性能网络框架用于学习 IO 多路复用、事件驱动模型。 项目搭建过程借助 AI 梳理架构思路、系统调用用法所有代码均由本人逐行手敲完成在 WSL 环境下使用 gdb 调试独立解决 Buffer 扩容、定时器堆、事件循环、timerfd 使用等各类编译与逻辑 bug。代码仅作学习交流不用于商用。项目简介模仿《Linux 高性能服务器编程》思想实现 Reactor 模型核心组件EventLoop: 事件循环主体封装 epoll_wait,驱动所有调度事件Channel封装fd,事件回调实现文件到业务的解耦3.Buffer:自动处理缓冲区解决TCP粘包问题4.TimerHeap:基于 timefd 实现定时任务管理超时问题5.TcpConnection:封装 TCP 连接管理读写缓冲区和协议解析环境与编译开发环境WSL2 Ubuntu/GCC构建工具CMake编译指令mkdir build cd build cmake .. make -j4 ./TcpServer核心代码Ⅰ.Bufferconst ssize_t n ::readv(fd,vec,2); if( n 0) { *savedErrno errno; } else if(static_cast size_t(n) writable) { //数据全部写入当前buffer writeIndex_ n; } else { //一部分写入临时栈缓冲区追加进buffer writeIndex_ buffer_.size(); append(extrabuf,n - writable); } return n; /*append 追加函数*/ void Buffer::append(const char* data,size_t len){ ensureWritable(len); std::copy(data,data len,buffer_.begin() writeIndex_); writeIndex_ len; } /*Retrieve 读取*/ void Buffer::retrieve(size_t len){ if(len readableBytes()) throw std::out_of_range(Buffer::retrieve); readIndex_ len; if(readIndex_ writeIndex_) retrieveAll(); }2.作用解决TCP粘包隔离系统调用read/write.提供用户层读写接口3.核心设计readIndex,writeIndex双指针自动扩容Ⅱ.Channel1.核心代码void Channel::handleEvent(){ if(revents_ (EPOLLERR | EPOLLHUP)){ if(errorCallback_) errorCallback_(); return; } if(revents_ (EPOLLIN | EPOLLPRI)){ if(readCallback_) readCallback_(); } if(revents_ EPOLLOUT){ if(writeCallback_) writeCallback_(); } }2.作用文件描述符 事件回调Ⅲ.EventLoop1.核心代码void EventLoop::removeChannel(Channel* ch){ int fd ch-fd(); auto it channelMap_.find(fd); if(it ! channelMap_.end()){ epoll_ctl(epollfd_,EPOLL_CTL_DEL,fd,nullptr); channelMap_.erase(it); } } void EventLoop::loop(){ while(!quit_){ int numEvents epoll_wait(epollfd_,events_.data(), static_castint(events_.size()),-1); if(numEvents 0){ if(errno EINTR) continue; std::cerr epoll_wait error std::endl; break; } for(int i 0;i numEvents;i){ int fd events_[i].data.fd; auto it channelMap_.find(fd); //需要 channelMap_ if(it ! channelMap_.end()){ Channel* ch it-second; ch-setRevents(events_[i].events); ch-handleEvent(); } } doPendingFunctors(); } } /*把进程加入队列*/ void EventLoop::queueInLoop(std::functionvoid() cb){ { std::lock_guardstd::mutex lock(mutex_); pendingFunctors_.push_back(std::move(cb)); } if(!isInLoopThread() || callingPendingFunctors_){ wakeup(); } }2.作用将时间从队列中移除或者加入3.核心设计loop是否加入事件Ⅳ.Timer第一段代码void Timer::start(){ if(isActive_) return; struct itimerspec ts; memset(ts,0,sizeof(ts)); ts.it_value.tv_sec interval_.count()/1000; ts.it_value.tv_nsec (interval_.count() % 1000)* 1000000; if(repeat_){ ts.it_interval ts.it_value; } if(timerfd_settime(timerfd_,0,ts,nullptr) -1){ perror(timerfd_settime); return; } isActive_ true; channel_-enableReading(); }isActive_: 防重复启动已经运行直接返回itimerspec ts:timerfd 的时间结构体it_value第一次到期延迟相对时间第二个参数传 0 代表相对it_interval:重复定时器的周期repeat_ true,就把周期赋值给it_interval实现循环定时单次定时器 it_interval 保持0timerfd_settime(timerfd_,0,ts,nullptr):设置 timerfd第二个参数是相对时间。channel_ -enableReading(): 把 timefd 的可读时间注册进 epoll.第二段代码void Timer::stop(){ if(!isActive_) return; struct itimerspec ts; memset(ts,0,sizeof(ts)); timerfd_settime(timerfd_,0,ts,nullptr); isActive_ false; channel_-disableAll(); }Ⅴ.TcpConnectionvoid TcpConnection::parseLengthHeader(){ while(true){ //检查是否有足够数据读取长度头 if(inputBuffer_.readableBytes() 4) break; //读取长度头网络序 uint32_t netLen; memcpy(netLen,inputBuffer_.peek(),4); uint32_t len ntohl(netLen); //检查消息长度合理性防止恶性攻击 if(len 65536) { std::cerr Invalid message length: len std::endl; close(); return; } //取出数据跳过长度头 inputBuffer_.retrieve(4); std::string message inputBuffer_.retrieveAsString(len); //调用消息回溯 if(messageCallback_){ messageCallback_(shared_from_this(),message.c_str(),message.size()); } } }1.HTTP协议支持 静态响应修改TcpConnection 增加 parseHttp() 方法检测GET / 请求相应格式”HTTP/1.1 200OK\r” 加上 “Content-Length”空行正文关键问题Content-Length 必须精准的匹配空行的长度2.wrk/ab 压测工具wrk多线程HTTP 压测工具输出QPS、延迟、错误问题所用时间。abApache Bench类似工具但是WSL的环境兼容性差-测试参数-t线程数、-c并发连接数、-d持续时间产出QPS ≈ 2200 WSL,延迟平均值8ms3、性能及调整优化问题QPS还是低于5000ms常见问题参考的系统调用recv/send、内存拷贝(Buffer 操作)、日志输出调优手段关闭调试日志 std::cout 重负载启用 TCP_NODELAY(禁用 Nagle算法减少小包延迟)增大Buffer 和 epoll 事件数组使用-O2编译优化效果QPS从越1600提升至220037%遇到的问题与积累我们对Markdown编辑器进行了一些功能拓展与语法支持除了标准的Markdown编辑器功能我们增加了如下几点新功能帮助你用它写博客1.单线程Reator的局限性第五天特点适合IO 密集型单核如果满了就达到性能上限瓶颈CPU 单核系统调用开销WSL 环境下的效率扩展方向多线程Reactor 主线程 accept 工作线程处理IO2.第四天-线程任务的安全性锁机制std::mutex 保护 pendingFunctors_,std::thread::id 判断线程归属eventfd ----- 跨线程唤醒机制设计思想实现“IO 线程 业务线程” 分离为后续的多线程 Reactor打基础3.其他问题1cpp中的函数修改了形参的数量注意头文件是否也相应修改2定义的时候注意是否和私有的名称一致是否都是类型名字3业务含义不是错误是正常状态EAGAIN 翻译资源暂时不可用请稍后重试。绝对不能当作失败处理标准处理逻辑把当前 fd 加入 IO 多路复用epoll/poll/select等待读等待EPOLLIN、写等待EPOLLOUT就绪就绪后再次执行读写操作。4std::make_shared C11就存在std::make_unique延后到c14方法一wakeupChannel_.reset(new Channel(this, wakeupFd_));// 或者wakeupChannel_ std::unique_ptr(new Channel(this, wakeupFd_));方法二# 指定C17set(CMAKE_CXX_STANDARD 17)set(CMAKE_CXX_STANDARD_REQUIRED ON)set(CMAKE_CXX_EXTENSIONS OFF)5)重复写了同一条命令因为改了好几遍代码必要的头文件用到了 #include sys/timerfd.htimerfd_create() //创建timerfdtimerfd_settime() //设置定时时长、启动定时器timerfd_gettime() // 获取剩余时间#include arpa/inet.h//提供 htonl,ntohl我写成了htol导出如果你有什么好的想法以及文中的错误欢迎来指正以及评论。导入关于博客的全部代码发表在了 github 网站欢迎查看和下载https://github.com/chenxueqing86/simple-reactor1

相关新闻

慢速英语故事听力训练:家庭关系修复场景与词汇精学

慢速英语故事听力训练:家庭关系修复场景与词汇精学

【慢速英语】Mom And Dad Split Home _ Can This Family Heal _,我读到的第一反应不是“零散句子背诵”,而是一个可以反复听的英语故事场景:父母分开以后,孩子如何面对两个家,家庭关系还有没有修复的可能。这种素材放在…

2026/9/3 15:37:46 阅读更多 →
plsql存储过程练习题

plsql存储过程练习题

# Oracle PL/SQL 练习题(10道,中等难度) 约束要求: 1. 允许:存储过程、自定义函数、IF判断、CASE、FOR/WHILE循环2. 禁止:触发器、异常处理块(EXCEPTION) 3. 环境:基于经典emp、dept表&#xff…

2026/9/3 15:37:46 阅读更多 →
游戏开发中如何通过状态同步与事件驱动架构避免团队战瞬间崩盘

游戏开发中如何通过状态同步与事件驱动架构避免团队战瞬间崩盘

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/3 15:37:46 阅读更多 →

最新新闻

multi-agent-brainstorming - SKILL

multi-agent-brainstorming - SKILL

name: multi-agent-brainstorming description: “Simulate a structured peer-review process using multiple specialized agents to validate designs, surface hidden assumptions, and identify failure modes before implementation.” risk: none source: community dat…

2026/9/4 17:59:42 阅读更多 →
react-native-skills - list-performance-item-memo

react-native-skills - list-performance-item-memo

title: 传递原始值到列表项以实现记忆化 impact: HIGH impactDescription: 使 memo() 比较更有效 tags: lists, performance, memo, primitives 传递原始值到列表项以实现记忆化 尽可能只传递原始值(字符串、数字、布尔值)作为 props 给列表项组件。原始…

2026/9/4 17:59:42 阅读更多 →
警惕新型电诈“数字逮捕”!人在家中坐、钱被远程“扣”:骗子的高压心理操纵全拆解

警惕新型电诈“数字逮捕”!人在家中坐、钱被远程“扣”:骗子的高压心理操纵全拆解

最新内容 微 信 搜索 网络研究观“您好,您名下涉嫌一起特大跨境洗钱案,请立即配合调查……”“由于涉案金额巨大,我们决定对你实施‘数字逮捕’,你必须24小时开启摄像头,不得挂断,不得向任何人泄露&#xf…

2026/9/4 17:59:42 阅读更多 →
古琴修复全流程:从面板裂缝到音色平衡的实战案例

古琴修复全流程:从面板裂缝到音色平衡的实战案例

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/4 17:59:42 阅读更多 →
AI图像模式识别与水印检测:频域分析实战指南

AI图像模式识别与水印检测:频域分析实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/4 17:59:42 阅读更多 →
用 git bisect 二分定位 Bug:告别盲翻提交历史

用 git bisect 二分定位 Bug:告别盲翻提交历史

如果说有一个命令让我在第一次用完之后,脑子里冒出来的第一句话是“这招也太好用了吧”,那一定是git bisect。这不是什么新插件,也不需要额外安装,Git 本身就自带,只是绝大多数人日常只把它当作提交代码的工具&#xf…

2026/9/4 17:58:42 阅读更多 →

日新闻

ESP32S2嵌入式收音机全栈开发实战指南

ESP32S2嵌入式收音机全栈开发实战指南

简介:本资源是一个基于ESP32-S2芯片的嵌入式综合实践项目,面向本科毕业设计、课程设计及实训开发人员,聚焦网络收音机与FM收音机双模功能实现,融合ESP-IDF框架、ESP-ADF音频开发库与LVGL图形界面库,具备完整软硬件协同…

2026/9/4 0:00:28 阅读更多 →
WorkBuddy+Python实战:从零搭建商品库存管理系统

WorkBuddy+Python实战:从零搭建商品库存管理系统

最近想自己动手做一个“商品库存管理系统”的人变多了。很多开网店、做小团队ERP选型、或者刚学Python的读者,不是不想用系统,而是被传统开发路径劝退了:要装数据库,要写后端接口,要学前端页面,还要考虑多人…

2026/9/4 0:00:28 阅读更多 →
旅游情感分析:基于Python的垂直场景深度解析

旅游情感分析:基于Python的垂直场景深度解析

简介:本资源是一份面向计算机专业本科生的毕业设计实践项目,聚焦旅游行业真实场景,解决旅游平台对用户评论情感倾向自动识别与管理的需求。系统基于Python 3.9.11与Anaconda环境构建,集成携程、马蜂窝双平台爬虫模块,并…

2026/9/4 0:00:28 阅读更多 →

周新闻

备战数据库管理工程师校招:索引、事务、备份恢复核心考点解析

备战数据库管理工程师校招:索引、事务、备份恢复核心考点解析

每年校招季我都会接触不少准备数据库方向笔试的同学,看到最多的状态就是:简历上写着“熟悉 MySQL”“了解索引优化”,一碰到数据库管理工程师的笔试卷,却在索引、事务、锁、备份恢复这些题目上翻车。网易这套 2018 校园招聘数据库…

2026/9/4 10:54:27 阅读更多 →
数字电路时序基石:深入理解建立时间与保持时间

数字电路时序基石:深入理解建立时间与保持时间

1. 这不是“背公式”的事:时间参数到底在约束什么你翻过数字电路教材,一定见过这两个词:建立时间(Setup Time)和保持时间(Hold Time)。它们常被并列写在触发器(Flip-Flop&#xff09…

2026/9/4 14:20:02 阅读更多 →
蓝桥杯国赛超声波测距机:从单片机原理到嵌入式系统实战

蓝桥杯国赛超声波测距机:从单片机原理到嵌入式系统实战

1. 项目缘起:从赛题到超声波测距机的诞生第八届蓝桥杯单片机设计与开发国赛的题目,我至今记忆犹新。它没有直接给出一个花哨的名字,而是用“超声波测距机”这个朴实无华的功能描述,精准地勾勒出了考核的核心。对于当时备赛的我而言…

2026/9/3 4:22:59 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/3 4:17:49 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/3 4:18:56 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/4 9:37:01 阅读更多 →