目录html
本篇结束muduo网络库部分学习的笔记,总结一下muduo网络库的模块组成,同时会提供笔记中个模块的实现代码,这些模块代码单独抽出同时去除了muduo中对boost的依赖,改用c++11中的组件或者用单独的类替换,会使得muduo的各个组件会更为简洁易学。
基于C++11的muduo :https://github.com/BethlyRoseDaisley/SimpleMuduo 代码可能还有些bug和不完善的地方,简单使用和学习的话彻底够用,也可自行完善。linux
muduo是一个高质量的事件驱动型的网络库,其核心代码不超过4500行,使用的non-blocking IO(IO multiplexing)+ one loop per
thread模型。此模型每一个IO线程里面只有一个事件循环(即一个Reactor),处理读写和定时事件,激活的事件经过回调方式提供用户处理业务逻辑。
在linux下的话,能够把事件当作一个文件描述符,换句话也就是说一个file descriptor只能由一个线程读写。
一个线程最多只有一个EventLoop,而EventLoop中的循环便是在不停的监视这些描述符,当描述符可读或可写的时候,经过回调函数提供给用户处理。
这样咱们能够很方便地把不一样的socket套接字的描述符放到不一样的线程去, 也能够把一些socket放到一个线程里,这样这些socket就是线程安全的,由于始终只有EventLoo所在线程在读写它们,极大的下降了咱们的编程复杂性。c++
使用起来的话,它对外看上去应该这个样子,EventLoop一直处在事件循环中,经过IO复用机制select/poll/epoll回调激活的事件。
git
muduo的组件大体可划分为 5个部分, Reactor、TimerQueue和Eventfd、Acceptor和Connector、TcpConnection、TcpServer和TcpClient。
muduo网络部分的简化类图
github
若是只注重服务端的话,能够TcpClient省去,Poller在muduo中是个纯虚基类,如今用poll(2)具体化它,省略它们后的结构应该是这样的。
EventLoop和Poller及Channel组成Reactor部分、Acceptor做为TcpServer的监听器、TcpConnection负责处理socket的读写等事件、而TcpServer处理TcpConnection读写完成后的回调事件。
编程
Reactor由三部分组成,EventLoop、Poller、Channel.
EventLoop
即IO线程中的事件循环.它能确保全部注册的事件都在EventLoop对象所在的线程中执行,不用考虑事件的并发。它是线程安全的,且容许其余线程往EventLoop里面塞东西。后端
Poller
是IO multiplexing的封装,它是EventLoop的组成,与EventLoop的生命期至关,为EventLoop提供poll()方法。缓存
Channel
每一个Channel对象自始至终只负责一个文件描述符(fd) 的IO事件分发,但它不拥有这个fd,也不会在析构的时候关闭这个fd。每一个Channel对象自始至终只属于一个EventLoop,所以每一个Channel对象都只属于某一个IO线程。 Channel会把不一样的IO事件分发为不一样的回调, 例如ReadCallback、 WriteCallback等安全
Reactor的实现笔记 muduo学习笔记(二)Reactor关键结构
Reactor部分实现源码及简单测试 : https://github.com/BethlyRoseDaisley/SimpleMuduo/tree/master/Reactor
Reactor的时序图 :
网络
TimerQueue
并未在类图中单独给出,它是EventLoop的组件,为EventLoop提供了定时任务,和周期任务的接口。经过注册一个Timerfd到Poller实现.
TimerQueue的实现笔记 muduo网络库学习笔记(三)TimerQueue定时器队列
TimerQueue实现部分源码及简单测试 : https://github.com/BethlyRoseDaisley/SimpleMuduo/tree/master/TimerQueue
Eventfd
这个就是其余线程能往EventLoop线程里面塞任务的实现核心,它是 一个事件文件描述符fd,EventLoop经过将它注册到Poller,当其余线程往EventLoop里面塞任务的时候,先将任务存储在EventLoop的容器中,而后激活Eventfd,处理容器中存储的任务,固然赛任务须要一把锁来保护。
Eventfd的实现笔记 muduo网络库学习笔记(四) 经过eventfd实现的事件通知机制
Acceptor
它是服务端TcpServer类的主要组件,封装服务端的链接监听部分,在非阻塞网络编程中,accept的描述符可读,代表有新的链接上来,链接创建后经过回调告知用户有新的链接上来。
Acceptor的笔记 muduo网络库学习笔记(五) 连接器Connector与监听器Acceptor
Acceptor实现部分源码及简单测试 : https://github.com/BethlyRoseDaisley/SimpleMuduo/tree/master/Acceptor
Acceptor的时序图 :
在非阻塞网络编程中,发起链接的基本方式是调用connect(2),当socket变得可写时代表链接创建完毕,可是其中要处理各类类型的错误,muduo中把它封装为Connector class.
Connector 和 Acceptor 设计思路基本一致,只是Acceptor经过判断套接字是否可读来执行回调,而Connector是判断套接字是否可写来执行回调,可是要注意的是socket可写不必定就是链接创建好了 , 当链接创建出错时,套接口描述符变成既可读又可写,这时咱们能够经过调用getsockopt来获得套接口上待处理的错误(SO_ERROR),若是错误是0表示链接成功。
Connector的笔记 muduo网络库学习笔记(五) 连接器Connector与监听器Acceptor
Connector实现部分源码及简单测试 : https://github.com/BethlyRoseDaisley/SimpleMuduo/tree/master/Connector
Connector的时序图 :
Buffer
muduo中的buffer经过vector和一个栈上空间实现,动态可调,其结构很精妙,感兴趣的话建议直接阅读陈硕Buffer部分设计的文章. 这个buffer主要作为TcpConnection的组件。
Socket
封装一个套接字,管理了这个套接字描述符的生命期,是TcpConnection的组件,TcpConnection 经过这个套接字描述符注册读写事件,SocketHelp一个纯接口文件,封装了Socket的操做接口。
TcpConnection
封装一条Tcp链接, 处理这条链接中的读写及错误,链接关闭等事件,这些事件会在TcpConnection的内部先进行处理,而后经过回调函数将TcpConnection缓冲的Buffer提供给用户处理。
Tcpserver
主要使用组件Acceptor,有新的链接到来时会new一个TcpConnection保存在ConnectionMaps(TcpConnection共享指针的一张映射表)中,经过建立时注册的名字索引管理全部的链接;有数据可读时经过MessgeCallBack回调提供用户使用。
TcpClient
主要组件Connector, 它的实现与TcpServer类似,只不过每一个TcpClient只管理一个TcpConnection。
Reactor部分和EventLoop的组件理解后,TcpConnection和TcpServer部分就很好看懂了,因此也没有单独写新的文章。
TcpServer实现部分源码及简单测试 : https://github.com/BethlyRoseDaisley/SimpleMuduo/tree/master/TcpServer
TcpClient实现部分源码及简单测试 : https://github.com/BethlyRoseDaisley/SimpleMuduo/tree/master/TcpClient
Tcpserver的时序图 :
AsyncLogging
一个C++Stream风格的多线程安全非阻塞日志,是muduo库中的另外一个部分组成。
这个日志使用了双缓冲机制,这样新建的日志没必要等待磁盘操做,也避免了每条新的日志都触发日志线程,而是将多条日志拼程一个大的buffer 和后端buffer交换,后端线程就实时将后端buffer写入本地文件. 至关于批处理,减小线程唤醒频率 ,大大下降开销。
另外 ,为了及时将 日志消息写入文件, 便是 buffer A 中尚未push进来日志 也会每周期执行一次上述的写入操做。
可是有个问题,若是宕机,宕机瞬间缓存中的日志确定是还没写完的。
用了一阵子,总的来讲,这个日志我的很喜欢,轻巧简洁,十分便利。
AsyncLogging日志的格式化部分实现笔记 一个轻巧高效的多线程c++stream风格异步日志(一)
、
AsyncLogging的双缓冲机制一个轻巧高效的多线程c++stream风格异步日志(二)
AsyncLogging的源码 : https://github.com/BethlyRoseDaisley/SimpleMuduo/tree/master/AsyncLogging
直接包含Logger.hh 和 AsycnLogging.hh便可直接使用。
AsyncLogging类结构 :