总结说的有的过大,算是对自己学习的一个总结,后续会不断补充。
muduo是基于非阻塞的IO和事件驱动的网络库。
muduo的整体结构时one loop per thread+threadpool,图如下:
mainReactor和subReactor都是EventLoop,在mainReactor中接收连接,把建立后的连接分发到subReactor中。
作者开始在muduo/base中封装了和网络无关的一些操作,如日志、时间、队列、互斥量、条件变量、线程、线程池等,给后面网络库的设计带来了极大便利。
在muduo/net中封装了和网络相关的操作,muduo是基于Reactor模式的设计的,结构如下:
1、EventLoop是整个模式的核心,它来管理所有事件。one loop per thread说明一个线程只能有一个EventLoop。它封装了eventfd和timerfd,用来唤醒等待在poll上的线程;eventfd是其他线程唤醒当前线程使用,把任务添加到EventLoop的任务队列后,如果不是EventLoop的owner线程,则要唤醒它来执行任务;timerfd用来实现定时。
2、Poller是个虚基类,真正调用的时PollPoller或EPollPoller。用来实现IO的复用,事件都注册到Poller中。
3、Channel和fd一一对应,虽然它不拥有fd,fd需要响应哪些事件都保存在Channel中,且有对应的回调函数。
4、TcpConnection是保存已经建立的连接,它的生命周期模式,因此采用shared_ptr来管理。它负责数据的发送和接收,负责socket fd的关闭。
5、Acceptor主要负责连接的建立,用在服务端。当建立连接后,它会把连接的控制权转交给TcpConnection。
6、TcpServer是服务端,有Acceptor,用Map保存了当前已经连接的TcpConnection。
7、Connector是负责发起连接的一方,用在客户端。发起连接比接收连接要难,非阻塞发起连接更难,要处理各种错误,还要考虑连接失败后如何处理。当连接成功后它会把控制权交给TcpConnection。
8、TcpClient是客户端,封装了Connector。
muduo网络库虽然是用C++编写,但是却没有用到面向对象,用的是基于对象。最大的特点就是到处可见boost::bind,采用绑定回调函数的手法,实现了事件和特定函数的绑定,更加易于理解和使用。
对象生命周期的管理使用了shared_ptr。多线程中,对象的声明周期难以管理,一个线程难以判断对象是否已经析构,作者shared_ptr来管理对象声明周期。使用weak_ptr防止对象间相互引用,造成内存永久不释放。对于类内部的一些对象,使用scoped_ptr来管理。
非阻塞网络库应用层为什么需要缓冲区,怎么设计缓冲区。发送过快,缓冲区增长太大怎么办。
只使用非递归的互斥量,编码逻辑相对简单。
使用前置声明减少.h文件的包含。
……待续