【epoll】epoll多路复用和Reactor设计思想
目录
1、Reactor设计思想
文章相关视频讲解:
C/C++ Linux服务器开发高级架构学习视频点击:C/C++Linux服务器开发/Linux后台架构师-学习视频
epoll原理剖析以及reactor模型应用
linux epoll网络编程细节处理
小前言:
Reactor必要
传统OIO模式
2.2 Reactor模式
2.3 单线程Reactor模式
单Reactor多线程模式:
2.4 多线程Reactor模式
封装Epoll实现并发
Reactor模式:
封装Epoll实现reactor模式的高性能并发服务器
epoll的api
Reactor模式:
EPOLL实现的要点
1、Reactor设计思想
小前言:
reactor是对epoll的一层封装 ,epoll是对io进行管理,reactor将对io的管理转化为对事件的管理
Reactor必要
传统OIO模式
如图2.1所示为传统IO模式处理示意图:
图中所示一般是一个请求一个单独的处理线程。
缺点:server的accpet操作是阻塞的,业务处理中的handler中的读写请求也是阻塞的。那么这样的一种IO模式将会导致一个线程的请求没有处理完成无法处理下一个请求,这样就大大降低了吞吐量,这将是一个严重的问题。
为了解决这种问题就出现了一个经典的模式——Connection Per Thread即一个线程处理一个请求。
对于每一个新的请求都会分配一个新的线程来处理,这样的好处就是每个socket的请求相互之间不受影响,每个请求的业务逻辑相互之间也不影响。任何socket的读写操作都不会影响到后面的请求。
缺点:不是每个链接都有请求发生,这样就浪费了很多的线程资源。
这个时候可以采用多路复用IO模型的方式来处理IO事件,使用Reactor将响应IO事件和业务处理分开,一个或多个线程来处理IO事件,然后将就绪得到事件分发到业务处理handlers线程去异步非阻塞处理。
2.2 Reactor模式
2.3 单线程Reactor模式
什么是单线程Reactor模式,单线程模式采用一个Reactor线程来【处理套接字、新连接的创建】,并且【将接收到的请求分发到处理器Handler中】。
如图2.2为简单的单线程Reactor模式示意图,Reactor和数据处理(handler)都在一个线程里,图2.2参考doug lea论文《Scalable IO in Java》论文。
图2.2单线程Reactor模式示意图
单Reactor多线程模式:
2.4 多线程Reactor模式
多线程reactor模式的设计思想就是将handler线程放入到线程次中,在多核的情况下也可以考虑多个Selector选择器来处理事件,如图2.3为简单的多线程Reactor示意图;
图2.3多线程Reactor模式示意图
关于C/C++ Linux后端开发网络底层原理知识 点击 学习资料 获取,内容知识点包括Linux,Nginx,ZeroMQ,MySQL,Redis,线程池,MongoDB,ZK,Linux内核,CDN,P2P,epoll,Docker,TCP/IP,协程,DPDK等等。
封装Epoll实现并发
第一次学epoll时,容易错误的认为epoll可以实现并发,其实正确的说法是借助epoll可以实现高性能并发服务器,epoll只是提供了IO复用,在IO复用,真正的并发只能通过线程进程实现。
Reactor模式:
Reactor模式实现非常简单,使用同步IO模型,即业务线程处理数据需要主动等待或询问,主要特点是利用epoll监听listen描述符是否有响应,及时将客户连接信息放于一个队列,epoll和队列都是在主进程/线程中,由子进程/线程来接管各个描述符,对描述符进行下一步操作,包括connect和数据读写。主程读写就绪事件。
大致流程图如下:
Preactor模式:
Preactor模式完全将IO处理和业务分离,使用异步IO模型,即内核完成数据处理后主动通知给应用处理,主进程/线程不仅要完成listen任务,还需要完成内核数据缓冲区的映射,直接将数据buff传递给业务线程,业务线程只需要处理业务逻辑即可。
大致流程如下:
封装Epoll实现reactor模式的高性能并发服务器
epoll的api
首先介绍epoll的api
int epoll_create(int size); // 创建epfd
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); //向epfd注册(fd,event)// epoll_event结构体定义
struct epoll_event {__uint32_t events; /* epoll 事件 */epoll_data_t data; /* 传递的数据,用于处理ready的fd,获得上下文关系 */
}
// data联合体,一般用其指针域ptr,因为要从这个data读取到上下文信息
typedef union epoll_data {void *ptr;int fd;uint32_t u32;uint64_t u64;
} epoll_data_t;// op宏/* EPOLL_CTL_ADD(注册新的fd到epfd)* EPOLL_CTL_MOD(修改已经注册的fd的监听事件)* EPOLL_CTL_DEL(epfd删除一个fd)*/
** events : {EPOLLIN, EPOLLOUT, EPOLLPRI, EPOLLHUP, EPOLLET, EPOLLONESHOT}*/int epoll_wait(int epfd, struct epoll_event *event, int maxevents, int timeout); //用于轮询注册的fd,若满足相应的注册事件,// 则结束epoll_wait阻塞
/* @param timeout 超时时间* -1: 永久阻塞* 0: 立即返回,非阻塞* >0: 指定微秒
*/
Reactor模式:
io模式的历程:
单线程,一般阻塞->多线程,一般阻塞(一条连接一线程)->线程池(减少线程创建销毁开销)->reactor(更小粒度的线程)
所谓更小的粒度的线程是指,传统的多线程是一个连接一个线程,粒度太大,比如可以把一个连接继续细分成三个步骤:read,process,send三个步骤,每个步骤占一个线程,处理完后交给主线程调度,进入下一个处理模块
EPOLL实现的要点
0. 创建epoll_fd = epoll_create(MAX_EVENT+1)
1. 维护event数组
1.1 一个交给epoll_wait维护(空的放进去,ready的出来)
1.1.1 特定的结构体 struct epoll_event
1.2 一个自己维护(维持对所有注册事件的监控)(全局)
1.2.1 由于自己维护,想怎么写怎么写,一般的会让epoll_event.data.ptr = myevent,以作为回调函数的参数,保持一个上下文关系
2. 创建并初始化事件(epoll_event)
2.1 结构体有两个字段 event和data , event是EPOLLIN这样的宏,data的作用是记录一些消息,这样ready的时候可以访问这个消息,比如fd, 回调函数指针,status等等
3. 向epfd注册事件
3.1 epoll_ctl(epfd , op_macro , target_fd , &epoll_event )
3.2 op_macro是代表epoll_ctl的类型,诸如EPOLL_CTL_ADD
3.3 target_fd是要监听的fd,比如tcp监听套接字ls_socket,epoll_event就是当事件发生时,epoll_wait()里面 event[]将会出现的结构体
4. 写回调函数
4.1 这是reactor模式的重点.
4.2 典型的,检测到ls_socket可读后(epoll_wait不再阻塞),进入回调函数(通过event[i].data.ptr->callback),假如命名为accept_fn(),在这个函数简单来看要做的事就是
1.conn_socket = accept(ls_socket)
2.创建,初始化epoll_event并注册到epfd(当然还要加进自己维护的fd列表),由于epoll是轮询的模式,需要将conn_socket用fcntl设为O_NONBLOCK,非阻塞.
4.3 这个不像select,需要每次重新加入fd到列表里面,注册一次即可
4.4 conn_socket被通过事件EPOLLIN注册到epfd,下一步马上的,epoll_wait检测出conn_socket可读(假设确实可读),然后回调进入recvdata函数(需要在创建并初始化epoll_event指定, 实际上是自定义一个结构体,让data.ptr指向这个结构体就行),一般的,就以这个结构体组成自己维护的fd list,
4.5 recvdata函数首先调用recv(fd,my_event->buf,...),把待发送的数据存在my_event->buf , 然后修改(fd,myevent)到epfd为发送事件EPOLLOUT,以及改变回调函数为callback_send
4.6 来到epoll_wait,检测到该fd可写,则回调进入senddata函数,该函数调用send(fd,myevent->buf)发送数据,然后修改fd的注册事件为EPOLLIN(即EPOLL_CTLMOD),清空my_event->buf....如此反复
注意点:
1. callback函数如何获得my_event? 我们在epoll_event中能获得event和data,在data.ptr中找到my_event,典型的my_event可能包括回调函数指针,event_type,fd,buf[BUFLEN],last_active_time,...
nfd = epoll_wait(epfd , epoll_events , MAX_EVENT+1 , 1000)
assert(nfd>0)
for i in range(nfd):my_event* ev = (my_event*) epoll_events[i].data.ptr// if (epoll_events[i].events& EPOLLIN){} 用按位与的方式检测相等,因为这种flag宏一般都是位不相同的// 用回调函数的方法时,不需要比较event_type,直接调用函数即可// ev->callback_fn(ev) 不可以 callback_fn的原型应该是void(*callvback_fn)(void*),// 因为定义callback原型的时候,ev还是不完整的类型ev->callback_fn((void*)ev)
【epoll】epoll多路复用和Reactor设计思想相关推荐
- Linux 底层原理 —— epoll 与多路复用
引言 epoll 是 Linux 系统下高性能网络服务的必备技术,很多面试中高频出现的 Nginx.Redis 都使用了这一技术,本文总结 linux 多路复用模型的演变过程,看一看epoll 是如何 ...
- epoll原理剖析以及reactor模型应用丨网络编程|网络IO|select|poll|socket|reactor多核实现丨c/c++linux服务器开发
epoll原理剖析以及reactor模型应用 视频讲解如下,点击观看: epoll原理剖析以及reactor模型应用丨网络编程|网络IO|select|poll|socket|reactor多核实现丨 ...
- epoll原理剖析以及reactor模型应用
epoll原理剖析以及reactor模型应用 1. epoll原理剖析 2. 单reactor原理以及应用 3. 多reactor原理以及应用 视频讲解如下,点击观看: epoll原理剖析以及re ...
- 深入理解消息队列(场景,对比,原理和设计思想)
导语 | 消息队列也通常称为消息中间件,提到消息队列,大部分互联网人或多或少都听过该名词.对于后端工程师而言,更是日常开发中必备的一项技能.随着大数据时代的到来,apache旗下的Kafka一度成为消 ...
- 消息队列背后的设计思想
作者:jaydenwen,腾讯 PCG 后台开发工程师 消息队列也通常称为消息中间件,提到消息队列,大部分互联网人或多或少都听过该名词.对于后端工程师而言,更是日常开发中必备的一项技能.随着大数据时代 ...
- redis核心原理与设计思想
redis核心原理与设计思想 一.redis的5种基本数据结构 1.String(字符串) redis字符串扩容策略 2.list(列表) list常用命令 右边进左边出:队列 右边进右边出:栈 快速 ...
- 【小家java】一个例子让就能你彻底理解Java的Future模式,Future类的设计思想
相关阅读 [小家java]java5新特性(简述十大新特性) 重要一跃 [小家java]java6新特性(简述十大新特性) 鸡肋升级 [小家java]java7新特性(简述八大新特性) 不温不火 [小 ...
- I/O多路复用以及Reactor 和 Proactor
本文内容为小林codig图解系统系列的知识点梳理,详细内容请移步原文 IO复用:https://blog.csdn.net/qq_34827674/article/details/115619261 ...
- AI框架精要:设计思想
AI框架精要:设计思想 本文主要介绍飞桨paddle平台的底层设计思想,可以帮助用户理解飞桨paddle框架的运作过程,以便于在实际业务需求中,更好的完成模型代码编写与调试及飞桨paddle框架的二次 ...
最新文章
- Android shape
- NOIP2012 D2 T2借教室
- 01 ORA系列:ORA-00904 标识符无效 invalid identifier
- 2022版全球及中国蓝宝石材料产业容量预测与十四五投资战略研究报告
- OpenCV信息流Alpha遮罩
- mendeley引用参考文献不显示_免费文献管理器Mendeley
- 解决 Azure AD 在 Azure Front Door 下登录失败的问题
- docker安装nginx,配置nginx,并成功访问
- sublime配置python编译环境及代码补全功能
- Vue项目中的RSA加解密
- Spring揭秘 读书笔记
- and or not 优先级_EXCEL函数与公式剖析:AND
- UG10.0 工程图 在注释的时候 引用/插入 组件尺寸
- jzoj 3426. 封印一击 (Standard IO)
- FormatdataLibsvm.xls的使用
- MySQL中修改密码及访问限制
- 感受5.12汶川大地震
- 基础的图书馆管理系统
- 关于使用GPS天线需要注意的事项
- Spring、Mybatis、Spring MVC整合实例
热门文章
- 如何开始一项可能帮助你走向人生巅峰的“业余项目”(Side Project)?
- Markdown 添加emoji表情
- macbookpro联网未能连接服务器,EasyConnect Mac连接不上终极解决
- Minecraft TrMenu 菜单插件 研究心得
- mac必备老牌下载器!Free Download Manager 6.12.1 中文版
- 深度估计软件DERS6.1使用方法
- MySQL面试必知必备必会50题(含代码)的测试表构建信息
- 学编程还不知道去哪找书?17个技术书籍资源网站,你一定要知道
- 动态规划常见类型总结
- 泛微流程表单中字段加sql_泛微全程电子化风控管理方案:风控、内控、合规一体化...