muduo源码学习(1)

来源:互联网 发布:mac ipython 编辑:程序博客网 时间:2024/06/01 09:25

c/c++服务器领域开源的网络库很多,如libevent,libev,libuv,asio等,学习了unix网络编程后,想学习一下网络库的实现。muduo库是陈硕的开源了网络库,核心代码量不是很大,而且不是跨平台的,没有一大堆为了支持跨平台的宏定义,可读性较高,用来学习还是不错的。为了简化,选择了早期的0.9.1版本。



首先看一下muduo的架构设计。muduo库的采用的是reactor模式,而且在多线程的设计上与netty很类似。采用的是non-blocking IO+one event loop per thread。翻译过来也就是非阻塞IO,还有就是在创建的线程里都是一个循环,在循环体中调用IO复用的函数,如epoll_wait(),poll()函数。在循环这些循环中不断的处理活跃的文件描述符读写事件,还有到期的定时事件,还有处理类似于任务队列中的任务。监听套接字所在的那个线程对于的循序比较特殊,可以称为是main reactor,可以不断的接受客户端的连接。其余的线程可以称为是sub reactor,监听连接套接字。sub reactor中的套接字可以有main reactor分配过来,做到负载均衡。而且sub reactor的数量是可以配置的,甚至可以为0,那样就是单线程模式。线程的数量可以根据机器的CPU数量来选择。整个线程的设计思路和netty非常类似。线程池Thread Pool是可以选择的组件,看具体的应用情况,如果计算任务比较多,可以选择合适的线程数量的线程池。


对于库的使用者来说,网络编程只需要关注连接的建立,断开,描述符的可读,可写,数据发送完毕等之类的事件。其实大多数网络库的设计都是如此。可以认为网络编程的底层的本质就是这些吧,使用者只需关注逻辑部分即可。为了封装成库,或者是框架,如果用c语言的话,就是定义出相应事件到了的函数指针类型,使用者根据函数指针类型编写相应的函数即可,然后这些函数的调用会在相应事件的到来时被框架调用,这就是所谓的回调函数。如果是采用面向对象风格的c++来编写的话,就要将这些函数编写成虚函数。使用者继承相应的类就行。这类似于设计模式中的模板模式。父类中的模板方法已经把一些函数的调用写好了,函数的类型已经定义好了,用户继承重写就行。然而muduo虽然是采用c++编写的,但并不是使用面向对象的思想,而是基于对象的思想,也就是muduo并不使用继承来实现,而是采用boost中的bind函数适配器来绑定对应事件的回调函数,类似于c语言中的函数指针吧。


网络库主要解决什么问题?如上图,对于这是一个简单的服务器运行流程。muduo网络库就是在此基础之上封装的。主要有连接的管理,epoll循环,事件的处理。有一个初学者容易忽视的是缓冲区的管理。TCP是流协议,容易出现粘包问题,还有网络状态不好的问题,这就需要引入应用层的发送和接受的缓冲区。比如发送缓冲区的管理,当向客户端发送数据时,一次只发送了一部分,剩下的就需要加入到发送缓冲区中缓存起来,并且关注描述符的可写事件。muduo在此基础之上封装,在epoll循环中加入了对定时事件的处理,还有对任务队列的处理。