# Easy Reactor
Easy-Reactor是一个基于Reactor模式的Linux C++网络服务器框架,支持多线程TCP服务器,单线程TCP服务器,单线程UDP服务器等形式,可以让使用者完全专注于业务,快速开发出一个高效的服务器应用。
在工作中开发基础服务器的经验总结、以及阅读陈硕《muduo》一书的收获,使得我以沉淀的心态做了这个项目
#### 性能一览
>服务器参数:
>CPU个数:24 内存:128GB 网卡队列个数:24
>
>测试程序:
>echo pingpong服务,每次传递100字节内容,见目录test/
| TCP服务线程数 | benchmark情况 | QPS |
| :-----: | :-----: | :-----: |
|1线程|5个benchmark,各建立100个连接| `10.96W/s` |
|3线程|5个benchmark,各建立100个连接| `31.06W/s` |
|5线程|5个benchmark,各建立100个连接| `48.12W/s` |
|8线程|9个benchmark,各建立100个连接| `59.79W/s` |
## 介绍
### IO Event: 基于epoll
一切IO事件设置为非阻塞,由Linux epoll进行管理,且TCP、UDP的可读、可写事件均以默认方式即水平模式注册
### Timer Event: Timer Queue设计
- 以最小堆管理Timers(注册Timer、删除Timer),以每个Timer的发生时间在最小堆中排序
- 以timerfd作为通知方式,交给eventLoop监听,将超时事件转为IO事件
- timerfd所设置的时间总是最小堆的堆顶Timer的发生时间
### EventLoop
IO Event与Timer Event全部在EventLoop中注册、监听、运行,一个EventLoop独占一个线程
### 功能
**对TCP服务器端:** 支持设置:收到某类消息后回调函数,连接接收后回调函数,连接关闭前回调函数;
**对TCP客户端:** 支持设置:收到某类消息后回调函数,connect成功后回调函数,连接关闭前回调函数;
**对UDP服务端、客户端:** 都仅支持收到某类消息后回调函数
各服务端、客户端都可以主动发消息
此外,对**多线程模式的TCP服务器** ,支持:向某个or ALL子线程发送待执行任务pendingTask回调函数,可以在一次poll循环后执行pendingTask内容
### TCP服务器架构:多线程Reactor
![Multi-Thread-Arch](pictures/multi-thread-arch.png)
多线程TCP服务器采用了one loop per thread模型(memcached、muduo也是这么干的)
主线程作为Accepter角色,线程池作为实际连接操作者TCPConnection,线程池每个线程运行EventLoop维护一定量的连接,管理这些连接的IO Event与Timer Event,线程池中每个线程初始时监听自己队列的eventfd,便于与主线程通信
#### Accepter细节
1. Accepter收到新连接,以Round-Robin轮询方法将连接发送到一个线程的队列,以交给此线程管理这个连接
2. Accepter已达连接上限时,使用占坑法处理
3. Accepter使用大数组管理所有连接信息,当一个连接关闭,并不立即清理TCPConnection对象,而是等待新连接到来后复用此对象(memcached也是这么干的)
#### 可写事件与busy loop
由于TCP socket写缓冲区总是准备好的(除非满了),如果一直监听EPOLLOUT事件会造成EventLoop产生busy loop现象,最严重会吃满CPU
故:
- 有数据要写时,才监听EPOLLOUT;
- 当所有数据已写到socket,立刻删除EPOLLOUT事件
#### 粘包处理
使用固定长度包头8字节(4字节存放消息类型,4字节存放消息body长度),任何在Easy-Reactor中发送的消息都会被默默加上这个包头
#### 消息分发
Server对象提供了:不同消息类型注册不同的回调函数功能,方便用户可以根据不同消息类型编写不同的处理函数
当读取socket数据后,如果包完整,则会根据消息类型ID,将一条 **完整的消息** 发给对应的回调函数去处理
#### 缓冲区管理
每个连接对象TCPConnection没必要一直持有着读缓冲区和写缓冲区:
预设我们需要的一个缓冲区大小64KB,则每个连接需要读、写缓冲区共128KB -> 当连接数变多,内存占用过大
实际上
- 对于读缓冲区,当读完全部数据且被处理后,读缓冲区就可以释放了,除非有粘包发生
- 对于写缓冲区,当全部数据被发送到socket,写缓冲区就可以释放了,除非有数据没发完
我设计了一个简单的缓冲区管理容器,预先分配各种大小的缓冲区若干:
4K缓冲区:5000个,16KB:1000个,64KB:500个,256KB:200个,1MB:50个,4MB:10个
而每个TCPConnection初始时是没有读写缓冲区的,当需要读写时就向管理器索要一个长度合适的缓冲区使用,使用完就归还。具体而言:
##### 每当TCPconnection读取数据:
- 先会利用`fcntl+FIONREAD`获取可读数据大小
- 如果有读缓冲区(说明上次粘包了,没归还),则看剩余缓冲区空间是否放得下新数据,能就放,不能就跟管理器要个新缓冲区替代了旧的,copy了旧缓冲区的数据后把旧的归还,把新可读数据放进来
- 如果没有读缓冲区(说明上次没粘包,归还了),则跟管理器要个缓冲区,把新可读数据放进来
- 当业务回调处理后发现缓冲区没更多数据了,归还;否则,将剩余数据移动到缓冲区头部,继续持有等待下次使用
##### 每当TCPconnection写数据:
- 用户调用sendData,如果有写缓冲区(说明上次每写完,不归还),则追加数据,如果放不下了,就跟管理器要个新缓冲区替代了旧的,copy了旧缓冲区的数据后把旧的归还,把新待发数据放进来
- 一次性把写缓冲区的数据发送给socket后,如果发送完成,则归还缓冲区;否则把剩余待发数据移动到缓冲区头部,继续持有等待下次使用
### UDP服务器架构:单线程Reactor
由于UDP是无连接的,多线程操作同一个UDP socket效率未必很高,故选择了单线程模型,图略因为很简单
使用者完全可以使用多线程,每个线程运行Easy-Reactor UDP服务器,即每个线程一个地址不同的UDP socket,可得到一定的并行能力
### TCP、UDP客户端
都是eventLoop方式
### 使用方法
以一个TCP的`pingpong echo server`为例(具体TCP、UDP、timer例子见example目录)
#### tcp server端:
![Server-Example](pictures/server-example.png)
#### tcp client端:
![Client-Example](pictures/client-example.png)
没有合适的资源?快使用搜索试试~ 我知道了~
温馨提示
Easy Reactor Easy-Reactor是一个基于Reactor模式的Linux C++网络服务器框架,支持多线程TCP服务器,单线程TCP服务器,单线程UDP服务器等形式,可以让使用者完全专注于业务,快速开发出一个高效的服务器应用。 在工作中开发基础服务器的经验总结、以及阅读陈硕《muduo》一书的收获,使得我以沉淀的心态做了这个项目 功能 对TCP服务器端: 支持设置:收到某类消息后回调函数,连接接收后回调函数,连接关闭前回调函数; 对TCP客户端: 支持设置:收到某类消息后回调函数,connect成功后回调函数,连接关闭前回调函数; 对UDP服务端、客户端: 都仅支持收到某类消息后回调函数 各服务端、客户端都可以主动发消息 此外,对多线程模式的TCP服务器 ,支持:向某个or ALL子线程发送待执行任务pendingTask回调函数,可以在一次poll循环后执行pendingTask内容
资源推荐
资源详情
资源评论
收起资源包目录
Easy-Reactor.zip (55个子文件)
makefile 574B
include
msg_head.h 694B
tcp_conn.h 602B
thread_pool.h 777B
udp_client.h 811B
tcp_server.h 2KB
thread_queue.h 2KB
timer_queue.h 954B
event_base.h 1KB
msg_dispatcher.h 1KB
net_commu.h 366B
udp_server.h 872B
io_buffer.h 2KB
tcp_client.h 2KB
easy_reactor.h 270B
event_loop.h 1KB
config_reader.h 1KB
print_error.h 1KB
pictures
multi-thread-arch.png 29KB
server-example.png 37KB
client-example.png 128KB
src
thread_pool.cc 3KB
tcp_client.cc 6KB
tcp_server.cc 6KB
tcp_conn.cc 4KB
io_buffer.cc 7KB
event_loop.cc 6KB
udp_client.cc 3KB
timer_queue.cc 4KB
config_reader.cc 6KB
udp_server.cc 3KB
LICENSE 1KB
test
makefile 394B
myconf.ini 43B
echoMsg.pb.h 8KB
server.cc 1007B
echoMsg.pb.cc 12KB
benchmark.cc 3KB
echoMsg.proto 112B
example
udpEchoServer
makefile 384B
echoMsg.pb.h 8KB
server.cc 1003B
echoMsg.pb.cc 12KB
echoMsg.proto 112B
client.cc 2KB
timerServer
makefile 267B
server.cc 878B
tcpEchoServer
makefile 384B
myconf.ini 43B
echoMsg.pb.h 8KB
server.cc 1007B
echoMsg.pb.cc 12KB
echoMsg.proto 112B
client.cc 2KB
README.md 6KB
共 55 条
- 1
资源评论
csdnGuoYuying
- 粉丝: 199
- 资源: 111
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- 基于matlab实现的谐波叠加法的风速时程曲线模拟程序.rar
- 基于matlab实现的人工蜂群算法的源代码,很好用,可以自己个别的修改下.rar
- 基于matlab实现的人工蜂群算法优化无刷直流电机PID控制
- 基于matlab实现的一个仿真单摆非线性振动的程序,可以计算单摆的分岔图 相图.rar
- 基于matlab实现的移动窗口算法平滑光谱矩阵,用于近红外等光谱数据的预处理 (1) - 副本.rar
- ModelLink旨在为华为 昇腾芯片 上的大语言模型提供端到端的解决方案, 包含模型,算法,以及下游任务
- 基于matlab实现的应用不同预处理及建模方法处理光谱数据 - 副本.rar
- 基于matlab实现的移动窗口算法平滑光谱矩阵,用于近红外等光谱数据的预处理.rar
- 基于matlab实现的用粒子群优化算法对三轴稳定航天器姿态控制PD参数进行自动寻优.rar
- 基于matlab实现的用感知器分类算法分离三类样本,每个分类面都将一类与其他所有的类分开.rar
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功