-
作者:陈硕
-
编程语言:C++
-
架构模式:Reactor
-
代码链接:GitHub - chenshuo/muduo: Event-driven network library for multi-threaded Linux server in C++11
-
设计自述:https://www.cnblogs.com/Solstice/archive/2010/08/29/muduo_net_lib.html
-
-
以下内容,主要援引于自述
-
设计目标
-
线程安全,支持多线程
-
只支持 Linux,不支持 Windows
-
IO multiplexing 使用 poll 和 epoll
-
主要支持 x86-64,兼顾 IA32
-
不支持 UDP,只支持 TCP
-
不支持 IPv6,只支持 IPv4
-
不考虑广域网应用,只考虑局域网
-
只支持一种使用模式:non-blocking IO + one event loop per thread,不考虑阻塞 IO
-
API 简单易用,只暴露具体类和标准库里的类,不使用 non-trivial templates,也不使用虚函数
-
只做 library,不做成 framework
-
争取全部代码在 5000 行以内(不含测试)
-
搭配 Google Protocol Buffers RPC
实现简述
Muduo
是基于Reactor
模式的网络库,其核心是个事件循环EventLoop
,用于响应计时器和IO
事件。Muduo
采用基于对象(object based
)而非面向对象(object oriented
)的设计风格,其接口多以boost::function + boost::bind
表达。
头文件关系
- 白底:public
- 黑底:private
接口细节
公开接口
-
Buffer
仿 Netty ChannelBuffer 的 buffer class,数据的读写通过 buffer 进行 -
InetAddress
封装 IPv4 地址 (end point),注意,muduo 目前不能解析域名,只认 IP -
EventLoop
反应器 Reactor,用户可以注册计时器回调 -
EventLoopThread
启动一个线程,在其中运行 EventLoop::loop() -
TcpConnection
整个网络库的核心,封装TCP
连接 -
TcpClient
用于编写网络客户端,能发起连接,并且有重试功能 -
TcpServer
用于编写网络服务器,接受客户的连接 -
在这些类中,
TcpConnection
的生命期依靠 shared_ptr 控制(即用户和库共同控制)。Buffer
的生命期由TcpConnection
控制。其余类的生命期由用户控制。 -
HttpServer 和 Inspector,暴露出一个 http 界面,用于监控进程的状态,类似于 Java JMX。这么做的原因是,《程序员修炼之道》第 6 章第 34 条提到“对于更大、更复杂的服务器代码,提供其操作的内部试图的一种漂亮技术是使用内建的 Web 服务器”,Jeff Dean 也说“(每个 Google 的服务器进程)Export HTML-based status pages for easy diagnosis”。
内部实现
-
Channel
是 Selectable IO channel,负责注册与响应 IO 事件,它不拥有 file descriptor。它是 Acceptor、Connector、EventLoop、TimerQueue、TcpConnection 的成员,生命期由后者控制。 -
Socket
封装一个 file descriptor,并在析构时关闭 fd。它是 Acceptor、TcpConnection 的成员,生命期由后者控制。EventLoop、TimerQueue 也拥有 fd,但是不封装为 Socket。 -
SocketsOps
封装各种 sockets 系统调用。 -
EventLoop
封装事件循环,也是事件分派的中心。它用 eventfd(2) 来异步唤醒,这有别于传统的用一对 pipe(2) 的办法。它用 TimerQueue 作为计时器管理,用 Poller 作为 IO Multiplexing。 -
Poller
是 PollPoller 和 EPollPoller 的基类,采用“电平触发”的语意。它是 EventLoop 的成员,生命期由后者控制。 -
PollPoller
和EPollPoller
封装 poll(2) 和 epoll(4) 两种 IO Multiplexing 后端。Poll 的存在价值是便于调试,因为 poll(2) 调用是上下文无关的,用 strace 很容易知道库的行为是否正确。 -
Connector
用于发起 TCP 连接,它是 TcpClient 的成员,生命期由后者控制。 -
Acceptor
用于接受 TCP 连接,它是 TcpServer 的成员,生命期由后者控制。 -
TimerQueue
用timerfd
实现定时,这有别于传统的设置 poll/epoll_wait 的等待时长的办法。为了简单起见,目前用链表来管理 Timer,如果有必要可改为优先队列,这样复杂度可从 O(n) 降为 O(ln n) (某些操作甚至是 O(1))。它是EventLoop
的成员,生命期由后者控制。 -
EventLoopThreadPool
用于创建IO
线程池,也就是说把 TcpConnection 分派到一组运行 EventLoop 的线程上。它是 TcpServer 的成员,生命期由后者控制。
线程模型
Muduo
的线程模型符合one loop per thread + thread pool
模型。
-
每个线程最多有一个
EventLoop
-
每个
TcpConnection
必须归某个EventLoop
管理:所有IO操作,所有FDFile Descriptor
读写
-
-
TcpConnection
所在的线程由其所属的EventLoop
决定 -
TcpConnection
和EventLoop
是线程安全的,可以跨线程调用
-
-
TcpServer
直接支持多线程,它有两种模式:
-
-
单线程,
Acceptor
与TcpConnection
用同一个线程做IO。 -
多线程,
Acceptor
与EventLoop
在同一个线程,另外创建一个EventLoopThreadPool
,新到的连接会按Round-Robin
方式分配到线程池中。
-