muduo是一个高质量的Reactor网络库,采用one loop per thread + thread loop架构实现,代码简洁,逻辑清晰,是学习网络编程的很好的典范。

  muduo的代码分为两部分,base和net,base部分实现一些基础功能,例如log, thread, threadpool, mutex, queue 等,这些基础模块在后面网络库中很多地方都可以复用, base库的类相互之间耦合性较低,源码阅读起来并不困难,此处不做过多探究。

 net部分使用base中的工具类实现更高层次的逻辑,网络编程无非是对socket和其使用的epoll/poll等进行封装,使其便于使用,屏蔽掉底层网络库的一些 "坑", 在满足了基础的网络IO之后,就需要考虑高性能,高并发的问题,muduo 的是由poll/epoll 这些异步IO构成,但是单个IO线程在面对大量请求时难免处理不过来,所以就需要结合多线程或者线程池,一个线程对应一个epoll进行网络IO,这样就可以充分利用硬件多核系统。从软硬两方面综合提升性能。net部分封装的较为彻底,对上层提供的接口简单易用,所以涉及复杂的内部处理,接下来就对其内部实现进行探究。

  下面这张图是陈硕提供的muduo 网络库的类图,本次讲解主要是围绕下面这张图,弄明白这样就相当于弄明白这个架构了。(图中灰色的类是内部类,白色的是外部类)

  首先是EvenLoop类,他是事件循环(反应器 Reactor),每个线程只能有一个 EventLoop 实体,它负责 IO 和定时器事件的分派。 它用 TimerQueue 作为计时器管理,用 Poller 作为 IO Multiplexing。TimeQueue底层使用timerfd_*系列函数将定时器转换为fd添加到事件循环中,当时间到达后就会自动触发事件, 其内部使用 set 管理一些注册好的Timer,由于set有自动排序功能,所以注册到事件循环的总是第一个需要处理的Timer。Poller是IO mutiplexing的实现,它是一个抽象类,具体实现由其子类PollPoller (封装poll), EpollPoller (封装epoll) 实现,这是muduo库中唯一一个用面向对象的思想实现的,通过虚函数提供回调功能。Poll中的updateChannel方法用于注册和更新关注的事件,所有的 fd 都需要调用它添加到事件循环中。 除了用TiemQueue和Poller管理时间事件和IO事件外,EvenLoop还包含一个任务队列,它用来做一些计算任务,你可以将自己的任务添加到任务队列中,EvenLoop在一次事件循环中处理完IO事件就会进行依次取出这些任务进行执行,这个设计在多线程中有极大的作用,当多个线程需要处理同一资源时可以避免加锁导致的性能受损, 可以将资源的管理固定地交由一个线程来处理,其他线程对资源的处理只需要添加到该线程的任务队列中,由该线程异步执行。 但是有一个问题,如果EvenLoop阻塞在epoll_wait处就无法处理这些计算任务了,毕竟计算任务是在处理完IO事件后才执行的,所以此时需要通过某种通信方式唤醒该线程,被唤醒后就取出队列中的任务进行执行。muduo采用 eventfd(2) 来异步唤醒。

  muduo中通过Channel对fd 进行封装,其实更合适的说法是对fd事件相关方法的封装,例如负责注册fd的可读或可写事件到EvenLoop,又如fd产生事件后要如何响应。 一个fd对应一个channel, 它们是聚合关系,Channel在析构函数中并不会close掉这个fd。 它有一个handleEvent方法,当该fd有事件产生时EvenLoop会调用handleEvent方法进行处理,在handleEvent内部根据可读或可写事件调用不同的回调函数(回调函数可事先注册)。 它一般做为其他类的成员,例如EvenLoop通过一个vector<Channel*> 对注册到其内的众多fd的管理,毕竟有了Channel就有了fd及其对应的事件处理方法,所以你会看到上图中EvenLoop与Channel是一对多的关系。

  Socket也是对fd的封装,但不同与channel, 它仅封装 ::socket 产生的fd, 并且提供的方法也是一些获取或设置网络连接属性的方法,他和 fd 是组合关系,当Socke析构时会close掉这个fd。不管如何封装fd, 一些系统函数传递的参数总是fd,所以你会看到上图中一些类中既有 fd 又有Channel或Socket, 这也是在所难免的。

  TcpConection是对一个连接的抽象,一个TcpConnection包含一个Socket和一个Channel,  上面说到channel::handleEvent会在产生事件后调用事先注册的回调函数,其实在TcpConnection构造的时候就会为其所属的Channel注册好这些回调函数,handleRead,handleWrite....分别对应可读可写事件产生后调用的回调函数。事件产生后会调用handleRead(或handleWrite), TcpConceton会在handleRead中做一些处理,然后转交给上层,提交到上层的具体体现就是调用上层注册的回调函数(又是一样的套路

muduo库整体架构简析的更多相关文章

  1. SequoiaDB 系列之四 :架构简析

    在本系列的第一篇中,简述了SequoiaDB的安装,以及一个(伪)集群的部署 第二篇和第三篇对SequoiaDB的集群,做了简单地操作. 在本篇中,将对SequoiaDB的架构进行简单的分析. 因为自 ...

  2. REST架构简析(原论文整理)

    0 引言        目前,互联网在社会中扮演的角色越来越重要.通过互联网为广大群众提供服务,也是互联网成功的关键.互联网服务架构目前大多数都是基于REST架构来完成的.REST从它诞生至今,可以说 ...

  3. Nginx服务器架构简析

    一.Nginx的模块化 模块化结构的思想是一个很久的概念,但也正是成熟的思想造就了Nginx的巨大优越性. 我们知道Nginx从总体上来讲是有许多个模块构成的.习惯将Nginx分为5大模块分别为:核心 ...

  4. 【超精简JS模版库/前端模板库】原理简析 和 XSS防范

    使用jsp.php.asp或者后来的struts等等的朋友,不一定知道什么是模版,但一定很清楚这样的开发方式: <div class="m-carousel"> < ...

  5. EasyPlayer RTSP安卓Android播放器架构简析

    本文转自EasyDarwin开源团队成员John的博客:http://blog.csdn.net/jyt0551/article/details/73310641 EasyPlayer 是一款小而美的 ...

  6. 构建 CDN 分发网络架构简析

    构建 CDN 分发网络架构 CDN的基本目的:1.通过本地缓存实现网站的访问速度的提升 CDN的关键点:CNAME在域名解析:split智能分发,引流到最近缓存节点

  7. Java Annotation 及几个常用开源项目注解原理简析

    PDF 版: Java Annotation.pdf, PPT 版:Java Annotation.pptx, Keynote 版:Java Annotation.key 一.Annotation 示 ...

  8. 《共享库PATH与ld.so.conf简析》

    这是摘抄<共享库PATH与ld.so.conf简析>1. 往/lib和/usr/lib里面加东西,是不用修改/etc/ld.so.conf的,但是完了之后要调一下ldconfig,不然这个 ...

  9. 3D文件压缩库——Draco简析

    3D文件压缩库——Draco简析 今年1月份时,google发布了名为“Draco”的3D图形开源压缩库,下载了其代码来看了下,感觉虽然暂时用不到,但还是有前途的,故简单做下分析. 注:Draco 代 ...

随机推荐

  1. java中集合框架

    java平台提供了一个全新的集合框架."集合框架"主要由一组用来操作对象的接口组成.不同接口描述一组不同数据类型. 在很大程度上,一旦您理解了接口,您就理解了框架.虽然您总要创建接 ...

  2. JS的组成部分、引入页面的方法以及命名规范

    JS的组成部分.引入页面的方法以及命名规范   一.页面是由三部分组成 1)html标签(超文本标记语言) 2)css样式(层叠样式表) 3)javascript脚本编程语言(动态脚本语言) 二.将c ...

  3. php绘图-报表

    1.PHP报表的创建,通过绘图,过程 要先开启gb库, 可以使用jpgraph(绘图框架)快速制作一些图形 报表的作用:可以制作一些统计图,地形图,分布图等,还可以做验证码图片(通过在画布上加字和干扰 ...

  4. spring mvc controller中获取request head内容

    spring mvc controller中获取request head内容: @RequestMapping("/{mlid}/{ptn}/{name}") public Str ...

  5. SSH系统介绍

    SSH的系统中,对象的调用流程是:JSP->Action->Service->DAO->Hibernate,数据的流向是ActionFormBean接受用户的数据,Action ...

  6. lufylegend库 LBitmapData LBitmap LSprite

    lufylegend库 LBitmapData LBitmap LSprite <!DOCTYPE html> <html lang="en"> <h ...

  7. 对lua中_ENV表的理解(lua5.2版本以后)

    当我拿到_ENV表的时候,会去想这个_ENV表是干什么用的? 首先看如下代码: print(_ENV) --0x1d005f0 print(_G) --0x1d005f0 ViewCode 看了上面的 ...

  8. C++ 头文件系列(forward_list)

    简介 forwrad_list字面意思为前向列表,但实际上它是一种单向列表,只能从单一方向遍历. 单向链表实现 forward_list内部是用单向列表实现的,并且设计该库的时候就是以近乎手写的单向链 ...

  9. POJ3254(入门状态压缩dp)

    Corn Fields Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 13203   Accepted: 6921 Desc ...

  10. 【G】开源的分布式部署解决方案(二) - 好项目是从烂项目基础上重构出来的

    分析目前项目结构 眼前出现这么一坨坨的文件夹,相信很多人已经看不下去了.是的,首先就是要把它给做掉. 按照这个项目文件夹的命名意图,大概可以划分如下: 1.Business:业务代码 2.Data:数 ...