目录

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设计思想相关推荐

  1. Linux 底层原理 —— epoll 与多路复用

    引言 epoll 是 Linux 系统下高性能网络服务的必备技术,很多面试中高频出现的 Nginx.Redis 都使用了这一技术,本文总结 linux 多路复用模型的演变过程,看一看epoll 是如何 ...

  2. epoll原理剖析以及reactor模型应用丨网络编程|网络IO|select|poll|socket|reactor多核实现丨c/c++linux服务器开发

    epoll原理剖析以及reactor模型应用 视频讲解如下,点击观看: epoll原理剖析以及reactor模型应用丨网络编程|网络IO|select|poll|socket|reactor多核实现丨 ...

  3. epoll原理剖析以及reactor模型应用

    epoll原理剖析以及reactor模型应用 1. epoll原理剖析  2. 单reactor原理以及应用  3. 多reactor原理以及应用 视频讲解如下,点击观看: epoll原理剖析以及re ...

  4. 深入理解消息队列(场景,对比,原理和设计思想)

    导语 | 消息队列也通常称为消息中间件,提到消息队列,大部分互联网人或多或少都听过该名词.对于后端工程师而言,更是日常开发中必备的一项技能.随着大数据时代的到来,apache旗下的Kafka一度成为消 ...

  5. 消息队列背后的设计思想

    作者:jaydenwen,腾讯 PCG 后台开发工程师 消息队列也通常称为消息中间件,提到消息队列,大部分互联网人或多或少都听过该名词.对于后端工程师而言,更是日常开发中必备的一项技能.随着大数据时代 ...

  6. redis核心原理与设计思想

    redis核心原理与设计思想 一.redis的5种基本数据结构 1.String(字符串) redis字符串扩容策略 2.list(列表) list常用命令 右边进左边出:队列 右边进右边出:栈 快速 ...

  7. 【小家java】一个例子让就能你彻底理解Java的Future模式,Future类的设计思想

    相关阅读 [小家java]java5新特性(简述十大新特性) 重要一跃 [小家java]java6新特性(简述十大新特性) 鸡肋升级 [小家java]java7新特性(简述八大新特性) 不温不火 [小 ...

  8. I/O多路复用以及Reactor 和 Proactor

    本文内容为小林codig图解系统系列的知识点梳理,详细内容请移步原文 IO复用:https://blog.csdn.net/qq_34827674/article/details/115619261 ...

  9. AI框架精要:设计思想

    AI框架精要:设计思想 本文主要介绍飞桨paddle平台的底层设计思想,可以帮助用户理解飞桨paddle框架的运作过程,以便于在实际业务需求中,更好的完成模型代码编写与调试及飞桨paddle框架的二次 ...

最新文章

  1. Android shape
  2. NOIP2012 D2 T2借教室
  3. 01 ORA系列:ORA-00904 标识符无效 invalid identifier
  4. 2022版全球及中国蓝宝石材料产业容量预测与十四五投资战略研究报告
  5. OpenCV信息流Alpha遮罩
  6. mendeley引用参考文献不显示_免费文献管理器Mendeley
  7. 解决 Azure AD 在 Azure Front Door 下登录失败的问题
  8. docker安装nginx,配置nginx,并成功访问
  9. sublime配置python编译环境及代码补全功能
  10. Vue项目中的RSA加解密
  11. Spring揭秘 读书笔记
  12. and or not 优先级_EXCEL函数与公式剖析:AND
  13. UG10.0 工程图 在注释的时候 引用/插入 组件尺寸
  14. jzoj 3426. 封印一击 (Standard IO)
  15. FormatdataLibsvm.xls的使用
  16. MySQL中修改密码及访问限制
  17. 感受5.12汶川大地震
  18. 基础的图书馆管理系统
  19. 关于使用GPS天线需要注意的事项
  20. Spring、Mybatis、Spring MVC整合实例

热门文章

  1. 如何开始一项可能帮助你走向人生巅峰的“业余项目”(Side Project)?
  2. Markdown 添加emoji表情
  3. macbookpro联网未能连接服务器,EasyConnect Mac连接不上终极解决
  4. Minecraft TrMenu 菜单插件 研究心得
  5. mac必备老牌下载器!Free Download Manager 6.12.1 中文版
  6. 深度估计软件DERS6.1使用方法
  7. MySQL面试必知必备必会50题(含代码)的测试表构建信息
  8. 学编程还不知道去哪找书?17个技术书籍资源网站,你一定要知道
  9. 动态规划常见类型总结
  10. 泛微流程表单中字段加sql_泛微全程电子化风控管理方案:风控、内控、合规一体化...