高效并发的网络框架大多离不开io多路复用函数,Linux下有三种
- select
- poll
- epoll
关于三者的区别可以参考 linux网络编程—–几种服务器模型及io多路复用函数
前段时间看Libevent源码时也学习过对epoll/poll/select的封装,但是毕竟c语言写的库,是通过函数指针实现多态。我学习的muduo源码是c++11版本的,利用c++进行封装。
首先复习一下C++面向对象和基于对象的区别
- 面向对象
- 面向对象的三大特点:封装,继承,多态缺一不可
- 封装:数据和处理数据的函数统一起来,封装在一个class中
- 继承:通过继承某个类派生出一个新类,被继承的类称作基类,派生出的类称作派生类。派生类是对基类的补充,二者之间满足一定的归属关心,如动物(基类),鸟(派生类)。继承可以是public/private/protected继承,也可以是虚继承(用于解决多重继承带来的重复问题),基类可以是抽象基类(不能被实例化),但是派生类需要重新实现基类定义的每个纯虚函数。
- 多态:在继承的基础上通过基类指针指向派生类的实例化对象,达到调用派生类虚函数的目的,多态又被叫做运行时多态,是在运行期根据基类指针实际指向的对象类型判断调用哪个函数的方式。
- 基于对象
- 无继承,无多态,只有封装
- 利用类封装好的接口实现对数据的操作
如何禁止编译器自动生成拷贝构造函数/赋值运算符
- 继承boost::noncopyable
- 自定义空基类,基类中将两个函数放在private域,派生类private继承该基类
- 在自己的private域中声明两个函数,不予实现
c++11版本采用第2中,boost版本采用第1中,第三种效果不好,因为错误是在链接期发现,前两个是在编译期
现如今大多C++程序都是基于对象的,面向对象只在整个程序中占一小部分比重。
muduo采用的也是基于对象的手法,但是对io多路复用的封装采用的是面向对象,即定义一个基类,派生出不同的派生类。muduo只派生了poll/epoll两个类封装,因为二者在实现上有相似性,可以共用基类。
基类Poller主要用于设计统一接口,两个派生类EPollPoller/PollPoller用于实现各自的操作,Poller定义如下
/* 禁止编译器自动生成拷贝构造函数/赋值操作运算符 */
class Poller : noncopyable
{
public:
typedef std