muduo reactor模式_木铎代码 - CSDN
  • Muduo 是我在业余时间编写的基于 Reactor 模式的 C++ 网络库,适用于 Linux 平台,支持多线程。本文主要介绍 muduo 网络库的使用。其设计与实现将有另文讲解。

    发布一个基于 Reactor 模式的 C++ 网络库

    陈硕 (giantchen_AT_gmail)

    Blog.csdn.net/Solstice

    2010 Aug 30

    本文主要介绍 muduo 网络库的使用。其设计与实现将有另文讲解。

    目录

    由来 1

    下载与编译 2

    例子 2

    基本结构 3

    公开接口 4

    内部实现 4

    线程模型 5

    结语 5

    由来

    半年前我写了一篇《学之者生,用之者死——ACE历史与简评》,其中提到“我心目中理想的网络库”的样子:

    • 线程安全,支持多核多线程
    • 不考虑可移植性,不跨平台,只支持 Linux,不支持 Windows。
    • 在不增加复杂度的前提下可以支持 FreeBSD/Darwin,方便将来用 Mac 作为开发用机,但不为它做性能优化。也就是说 IO multiplexing 使用 poll 和 epoll。
    • 主要支持 x86-64,兼顾 IA32
    • 不支持 UDP,只支持 TCP
    • 不支持 IPv6,只支持 IPv4
    • 不考虑广域网应用,只考虑局域网
    • 只支持一种使用模式:non-blocking IO + one event loop per thread,不考虑阻塞 IO
    • API 简单易用,只暴露具体类和标准库里的类,不使用 non-trivial templates,也不使用虚函数
    • 只满足常用需求的 90%,不面面俱到,必要的时候以 app 来适应 lib
    • 只做 library,不做成 framework
    • 争取全部代码在 5000 行以内(不含测试)
    • 以上条件都满足时,可以考虑搭配 Google Protocol Buffers RPC

    在想清楚这些目标之后,我开始第三次尝试编写自己的 C++ 网络库。与前两次不同,这次我一开始就想好了库的名字,叫 muduo (木铎),并在 Google code 上创建了项目: http://code.google.com/p/muduo/ 。muduo 的主体内容在 5 月底已经基本完成,现在我把它开源。

    本文主要介绍 muduo 网络库的使用,其设计与实现将有另文讲解。

    下载与编译

    下载地址: http://muduo.googlecode.com/files/muduo-0.1.0-alpha.tar.gz

    SHA1 Checksum: 5d3642e311177ded89ed0d15c10921738f8c984c

    Muduo 使用了 Linux 较新的系统调用,要求 Linux 的内核版本大于 2.6.28 (我自己用的是 2.6.32 )。在 Debian Squeeze / Ubuntu 10.04 LTS 上编译测试通过,32 位和 64 位系统都能使用。

    Muduo 采用 CMake 为 build system,安装方法:

    $ sudo apt-get install cmake

    Muduo 依赖 Boost,很容易安装:

    $ sudo apt-get install libboost1.40-dev # 或 libboost1.42-dev

    编译方法很简单:

    $ tar zxf muduo-0.1.0-alpha.tar.gz

    $ cd muduo/

    $ ./build.sh

    # 编译生成的可执行文件和静态库文件分别位于 ../build/debug/{bin,lib}

    如果要编译 release 版,可执行

    $ BUILD_TYPE=release ./build.sh

    # 编译生成的可执行文件和静态库文件分别位于 ../build/release/{bin,lib}

    编译完成之后请试运行其中的例子。比如 bin/inspector_test ,然后通过浏览器访问 http://10.0.0.10:12345/ 或 http://10.0.0.10:12345/proc/status,其中 10.0.0.10 替换为你的 Linux box 的 IP。

    例子

    Muduo 附带了几十个小例子,位于 examples 目录。其中包括从 Boost.Asio、JBoss Netty、Python Twisted 等处移植过来的例子。

    examples

    |-- simple # 简单网络协议的实现

    |   |-- allinone  # 在一个程序里同时实现下面 5 个协议

    |   |-- chargen   # RFC 864,可测试带宽

    |   |-- daytime # RFC 867

    |   |-- discard # RFC 863

    |   |-- echo # RFC 862

    |   |-- time # RFC 868

    |   `-- timeclient # time 协议的客户端

    |-- hub # 一个简单的 pub/sub/hub 服务,演示应用级的广播

    |-- roundtrip # 测试两台机器的网络延时与时间差

    |-- asio # 从 Boost.Asio 移植的例子

    |   |-- chat # 聊天服务

    |   `-- tutorial # 一系列 timers

    |-- netty # 从 JBoss Netty 移植的例子

    |   |-- discard # 可用于测试带宽,服务器可多线程运行

    |   |-- echo # 可用于测试带宽,服务器可多线程运行

    |   `-- uptime # TCP 长连接

    `-- twisted # 从 Python Twisted 移植的例子

        `-- finger # finger01 ~ 07

    基本结构

    Muduo 的目录结构如下。

    muduo

    |-- base # 与网络无关的基础代码,已提前发布

    `-- net # 网络库

        |-- http # 一个简单的可嵌入的 web 服务器

        |-- inspect # 基于以上 web 服务器的“窥探器”,用于报告进程的状态

        `-- poller # poll(2) 和 epoll(4) 两种 IO multiplexing 后端

    Muduo 是基于 Reactor 模式的网络库,其核心是个事件循环 EventLoop,用于响应计时器和 IO 事件。Muduo 采用基于对象(object based)而非面向对象(object oriented)的设计风格,其接口多以 boost::function + boost::bind 表达

    Muduo 的头文件明确分为客户可见和客户不可见两类。客户可见的为白底,客户不可见的为灰底。

    inc

    这里简单介绍各个头文件及 class 的作用,详细的介绍留给以后的博客。

    公开接口
    • 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_class_diagram

    线程模型

    Muduo 的线程模型符合我主张的 one loop per thread + thread pool 模型。每个线程最多有一个 EventLoop。每个 TcpConnection 必须归某个 EventLoop 管理,所有的 IO 会转移到这个线程,换句话说一个 file descriptor 只能由一个线程读写。TcpConnection 所在的线程由其所属的 EventLoop 决定,这样我们可以很方便地把不同的 TCP 连接放到不同的线程去,也可以把一些 TCP 连接放到一个线程里。TcpConnection 和 EventLoop 是线程安全的,可以跨线程调用。TcpServer 直接支持多线程,它有两种模式:

    1. 单线程,accept 与 TcpConnection 用同一个线程做 IO。

    2. 多线程,accept 与 EventLoop 在同一个线程,另外创建一个 EventLoopThreadPool,新到的连接会按 round-robin 方式分配到线程池中。

    结语

    Muduo 是我对常见网络编程任务的总结,用它我能很容易地编写多线程的 TCP 服务器和客户端。Muduo 是我业余时间的作品,代码估计还有很多 bug,功能也不完善(例如不支持 signal 处理),待日后慢慢改进吧。

     

    后记:性能测试:

    1. muduo 与 boost asio 吞吐量对比

    2. muduo 与 libevent2 吞吐量对比

    3. 击鼓传花:对比 muduo 与 libevent2 的事件处理效率

    展开全文
  • 公布一个基于 Reactor 模式的 C++ 网络库 陈硕 (giantchen_AT_gmail) Blog.csdn.net/Solstice 2010 Aug 30 本文主要介绍 muduo 网络库的使用。其设计与实现将有另文解说。 文件夹 由来 1 下载与编译 2 样例 ...

    公布一个基于 Reactor 模式的 C++ 网络库

    陈硕 (giantchen_AT_gmail)

    Blog.csdn.net/Solstice

    2010 Aug 30

    本文主要介绍 muduo 网络库的使用。其设计与实现将有另文解说。

    文件夹

    由来 1

    下载与编译 2

    样例 2

    基本结构 3

    公开接口 4

    内部实现 4

    线程模型 5

    结语 5

    由来

    半年前我写了一篇《学之者生,用之者死——ACE历史与简评》,当中提到“我心目中理想的网络库”的样子:

    • 线程安全,支持多核多线程
    • 不考虑可移植性,不跨平台,仅仅支持 Linux,不支持 Windows。
    • 在不添加复杂度的前提下能够支持 FreeBSD/Darwin,方便将来用 Mac 作为开发用机,但不为它做性能优化。也就是说 IO multiplexing 使用 poll 和 epoll。
    • 主要支持 x86-64,兼顾 IA32
    • 不支持 UDP,仅仅支持 TCP
    • 不支持 IPv6,仅仅支持 IPv4
    • 不考虑广域网应用,仅仅考虑局域网
    • 仅仅支持一种使用模式:non-blocking IO + one event loop per thread,不考虑堵塞 IO
    • API 简单易用,仅仅暴露详细类和标准库里的类,不使用 non-trivial templates,也不使用虚函数
    • 仅仅满足经常使用需求的 90%,不面面俱到,必要的时候以 app 来适应 lib
    • 仅仅做 library,不做成 framework
    • 争取所有代码在 5000 行以内(不含測试)
    • 以上条件都满足时,能够考虑搭配 Google Protocol Buffers RPC

    在想清楚这些目标之后,我開始第三次尝试编写自己的 C++ 网络库。与前两次不同,这次我一開始就想好了库的名字,叫 muduo (木铎),并在 Google code 上创建了项目: http://code.google.com/p/muduo/ 。muduo 的主体内容在 5 月底已经基本完毕,如今我把它开源。

    本文主要介绍 muduo 网络库的使用,其设计与实现将有另文解说。

    下载与编译

    下载地址: http://muduo.googlecode.com/files/muduo-0.1.0-alpha.tar.gz

    SHA1 Checksum: 5d3642e311177ded89ed0d15c10921738f8c984c

    Muduo 使用了 Linux 较新的系统调用,要求 Linux 的内核版本号大于 2.6.28 (我自己用的是 2.6.32 )。在 Debian Squeeze / Ubuntu 10.04 LTS 上编译測试通过,32 位和 64 位系统都能使用。

    Muduo 採用 CMake 为 build system,安装方法:

    $ sudo apt-get install cmake

    Muduo 依赖 Boost,非常easy安装:

    $ sudo apt-get install libboost1.40-dev # 或 libboost1.42-dev

    编译方法非常easy:

    $ tar zxf muduo-0.1.0-alpha.tar.gz

    $ cd muduo/

    $ ./build.sh

    # 编译生成的可运行文件和静态库文件分别位于 ../build/debug/{bin,lib}

    假设要编译 release 版,可运行

    $ BUILD_TYPE=release ./build.sh

    # 编译生成的可运行文件和静态库文件分别位于 ../build/release/{bin,lib}

    编译完毕之后请试执行当中的样例。比方 bin/inspector_test ,然后通过浏览器訪问 http://10.0.0.10:12345/ 或 http://10.0.0.10:12345/proc/status,当中 10.0.0.10 替换为你的 Linux box 的 IP。

    样例

    Muduo 附带了几十个小样例,位于 examples 文件夹。当中包含从 Boost.Asio、JBoss Netty、Python Twisted 等处移植过来的样例。

    examples

    |-- simple # 简单网络协议的实现

    |   |-- allinone  # 在一个程序里同一时候实现以下 5 个协议

    |   |-- chargen   # RFC 864,可測试带宽

    |   |-- daytime # RFC 867

    |   |-- discard # RFC 863

    |   |-- echo # RFC 862

    |   |-- time # RFC 868

    |   `-- timeclient # time 协议的客户端

    |-- hub # 一个简单的 pub/sub/hub 服务,演示应用级的广播

    |-- roundtrip # 測试两台机器的网络延时与时间差

    |-- asio # 从 Boost.Asio 移植的样例

    |   |-- chat # 聊天服务

    |   `-- tutorial # 一系列 timers

    |-- netty # 从 JBoss Netty 移植的样例

    |   |-- discard # 可用于測试带宽,server可多线程执行

    |   |-- echo # 可用于測试带宽,server可多线程执行

    |   `-- uptime # TCP 长连接

    `-- twisted # 从 Python Twisted 移植的样例

        `-- finger # finger01 ~ 07

    基本结构

    Muduo 的文件夹结构例如以下。

    muduo

    |-- base # 与网络无关的基础代码,已提前公布

    `-- net # 网络库

        |-- http # 一个简单的可嵌入的 web server

        |-- inspect # 基于以上 web server的“窥探器”,用于报告进程的状态

        `-- poller # poll(2) 和 epoll(4) 两种 IO multiplexing 后端

    Muduo 是基于 Reactor 模式的网络库,其核心是个事件循环 EventLoop,用于响应计时器和 IO 事件。Muduo 採用基于对象(object based)而非面向对象(object oriented)的设计风格,其接口多以 boost::function + boost::bind 表达

    Muduo 的头文件明白分为客户可见和客户不可见两类。客户可见的为白底,客户不可见的为灰底。

    inc

    这里简介各个头文件及 class 的作用,具体的介绍留给以后的博客。

    公开接口
    • Buffer 仿 Netty ChannelBuffer 的 buffer class,数据的读写透过 buffer 进行
    • InetAddress 封装 IPv4 地址 (end point),注意,muduo 眼下不能解析域名,仅仅认 IP
    • EventLoop 反应器 Reactor,用户能够注冊计时器回调
    • EventLoopThread 启动一个线程,在当中执行 EventLoop::loop()
    • TcpConnection 整个网络库的核心,封装一次 TCP 连接
    • TcpClient 用于编写网络client,能发起连接,而且有重试功能
    • TcpServer 用于编写网络server,接受客户的连接
    • 在这些类中,TcpConnection 的生命期依靠 shared_ptr 控制(即用户和库共同控制)。Buffer 的生命期由 TcpConnection 控制。其余类的生命期由用户控制。
    • HttpServer 和 Inspector,暴露出一个 http 界面,用于监控进程的状态,相似于 Java JMX。这么做的原因是,《程序猿修炼之道》第 6 章第 34 条提到“对于更大、更复杂的server代码,提供其操作的内部试图的一种美丽技术是使用内建的 Web server”,Jeff Dean 也说“(每一个 Google 的server进程)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 非常easy知道库的行为是否正确。
    • 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_class_diagram

    线程模型

    Muduo 的线程模型符合我主张的 one loop per thread + thread pool 模型。每一个线程最多有一个 EventLoop。每一个 TcpConnection 必须归某个 EventLoop 管理,全部的 IO 会转移到这个线程,换句话说一个 file descriptor 仅仅能由一个线程读写。TcpConnection 所在的线程由其所属的 EventLoop 决定,这样我们能够非常方便地把不同的 TCP 连接放到不同的线程去,也能够把一些 TCP 连接放到一个线程里。TcpConnection 和 EventLoop 是线程安全的,能够跨线程调用。TcpServer 直接支持多线程,它有两种模式:

    1. 单线程,accept 与 TcpConnection 用同一个线程做 IO。

    2. 多线程,accept 与 EventLoop 在同一个线程,另外创建一个 EventLoopThreadPool,新到的连接会按 round-robin 方式分配到线程池中。

    结语

    Muduo 是我对常见网络编程任务的总结,用它我能非常easy地编写多线程的 TCP server和client。Muduo 是我业余时间的作品,代码预计还有非常多 bug,功能也不完好(比如不支持 signal 处理),待日后慢慢改进吧。

     

    后记:性能測试:

    1. muduo 与 boost asio 吞吐量对照

    2. muduo 与 libevent2 吞吐量对照

    3. 击鼓传花:对照 muduo 与 libevent2 的事件处理效率

    转载于:https://www.cnblogs.com/zfyouxi/p/4500133.html

    展开全文
  • muduo木铎学习(一)

    2019-04-28 10:01:30
    相关的名词解释: ...Reactor 模式:反应器设计模式,处理并发服务请求,并将请求提交到一个或 者多个服务处理程序的事件设计模式。当客户端请求抵达后,服务处理程序使用多路分配策略, 由一个非阻塞的线程来...

    作者原文:https://blog.csdn.net/Solstice/article/details/5848547#_Toc17667

    相关的名词解释:

    1.一个基于 Reactor 模式的 C++ 网络库
    Reactor 模式:反应器设计模式,处理并发服务请求,并将请求提交到一个或
    者多个服务处理程序的事件设计模式。当客户端请求抵达后,服务处理程序使用多路分配策略,
    由一个非阻塞的线程来接收所有的请求,然后派发这些请求至相关的工作线程进行处理。
    (用单线程做多线程的事)

    2. non-trivial templates
    Trivial(平凡)和Non-Trivial(不平凡)是对于class(类)的或者类中的四个函数而言的:
    1.构造函数
    2.拷贝构造函数
    3.赋值函数
    4.析构函数
    Non-Trivial如果上面四种函数满足以下三点任意一项或一项以上:
    1.有基类
    2.显式(explict)定义了以上四种函数一种或以上
    3.类里有非静态非POD的数据成员
    那么该类就是Non-Trivial(不平凡)有意义的,所以有意义(Non-Trivial)的函数都有一些“多余”的操作,和系统自动创建的默认缺省函数有些差别。而有意义(Non-Trivial)的类则是含有Non-Trivial的函数。

    3.IA32 
    Intel Architecture 32bit英特尔32位体系架构
    4.FreeBSD
    一种类UNIX操作系统,内部结构和系统API上和UNIX有很大的兼容性。
    5.Darwin
    苹果电脑于2000年所释出的一个开放原始码操作系统。Darwin 是MacOSX 操作环境的操作系统成份

    6.I/O模式
    -- 阻塞 I/O(blocking IO)
    -- 非阻塞 I/O(nonblocking IO)
    -- I/O 多路复用( IO multiplexing)
    -- 信号驱动 I/O( signal driven IO)
    -- 异步 I/O(asynchronous IO)
    7.IO multiplexing有三种复用方式
    select()
    poll() IO多路复用
    epoll IO多路复用
    参考:https://blog.csdn.net/davidsguo008/article/details/73556811

    8.基于对象和面向对象的区别
    只有完全具有封装、继承、多态三大特点的才能够叫做面向对象,否则即使设计中蕴含了一些对象的概念,也顶多称为基于对象。
    通常基于对象是使用对象,意味着它们有像C++的结构加函数这样的对象,然而这只是到达面向对象语言的一部分,停留在把函数捆绑在结构内部的语言是基于对象的。但是无法利用现有的对象模板产生新的对象类型,继而产生新的对象,也就是说基于对象一般没有继承的特点。没有了继承的概念也就无从谈论多态。现在的很多流行技术都是基于对象的,它们使用一些封装好的对象,调用对象的方法,设置对象的属性。但是它们无法让程序员派生新对象类型。他们只能使用现有对象的方法和属性。所以当你判断一个新的技术是否是面向对象的时候,通常可以使用后两个特性来加以判断。例如:C++是面向对象的,而VB只是基于对象的。
    ADT(Abstract Data Type)是指一个数学模型以及定义在该模型上的一组操作。ADT包括数据数据元素,数据关系以及相关的操作。

    头文件分类:白色用户可见,灰色不可见

    9.non-trivial有用的
    面向对象与基于对象:
    library和framework的区别:
    library中类相对比较独立,编写时需要编写一些“胶水代码”来粘合
    framework是能够运用于特定应用领域的,不需要编写过多的“胶水代码”来粘合
    重要区别:框架提供用户注册的一些回调函数,使得框架能够调用我们所编写的回调函数,这就使得控制反转了。

    .cc文件是Linux/Unix下为C++源文件的默认扩展名,与.cpp(windows下)一个意思

    用GCC/G++在 Linux/Unix下可以打开和编译。用一般的记事本就可以打开和编辑。

     

    面向对象/基于对象

    基于对象的效率稍高一点点

    展开全文
  • 本文主要介绍 muduo 网络库的使用。其设计与实现将有另文讲解。 目录 由来 1 下载与编译 2 ...由来半年前我写了一篇《学之者生,用之者死——ACE历史与简评》,其中提到“我心目中理想的网络库”的样子: ...


    本文主要介绍 muduo 网络库的使用。其设计与实现将有另文讲解。

    目录

    由来 1

    下载与编译 2

    例子 2

    基本结构 3

    公开接口 4

    内部实现 4

    线程模型 5

    结语 5

    由来
    半年前我写了一篇《学之者生,用之者死——ACE历史与简评》,其中提到“我心目中理想的网络库”的样子:

    线程安全,支持多核多线程
    不考虑可移植性,不跨平台,只支持 Linux,不支持 Windows。
    在不增加复杂度的前提下可以支持 FreeBSD/Darwin,方便将来用 Mac 作为开发用机,但不为它做性能优化。也就是说 IO multiplexing 使用 poll 和 epoll。
    主要支持 x86-64,兼顾 IA32
    不支持 UDP,只支持 TCP
    不支持 IPv6,只支持 IPv4
    不考虑广域网应用,只考虑局域网
    只支持一种使用模式:non-blocking IO + one event loop per thread,不考虑阻塞 IO
    API 简单易用,只暴露具体类和标准库里的类,不使用 non-trivial templates,也不使用虚函数
    只满足常用需求的 90%,不面面俱到,必要的时候以 app 来适应 lib
    只做 library,不做成 framework
    争取全部代码在 5000 行以内(不含测试)
    以上条件都满足时,可以考虑搭配 Google Protocol Buffers RPC
    在想清楚这些目标之后,我开始第三次尝试编写自己的 C++ 网络库。与前两次不同,这次我一开始就想好了库的名字,叫 muduo (木铎),并在 Google code 上创建了项目: http://code.google.com/p/muduo/ 。muduo 的主体内容在 5 月底已经基本完成,现在我把它开源。

    本文主要介绍 muduo 网络库的使用,其设计与实现将有另文讲解。

    下载与编译
    下载地址: http://muduo.googlecode.com/files/muduo-0.1.0-alpha.tar.gz

    SHA1 Checksum: 5d3642e311177ded89ed0d15c10921738f8c984c

    Muduo 使用了 Linux 较新的系统调用,要求 Linux 的内核版本大于 2.6.28 (我自己用的是 2.6.32 )。在 Debian Squeeze / Ubuntu 10.04 LTS 上编译测试通过,32 位和 64 位系统都能使用。

    Muduo 采用 CMake 为 build system,安装方法:

    $ sudo apt-get install cmake

    Muduo 依赖 Boost,很容易安装:

    $ sudo apt-get install libboost1.40-dev # 或 libboost1.42-dev

    编译方法很简单:

    $ tar zxf muduo-0.1.0-alpha.tar.gz

    $ cd muduo/

    $ ./build.sh

    # 编译生成的可执行文件和静态库文件分别位于 ../build/debug/{bin,lib}

    如果要编译 release 版,可执行

    $ BUILD_TYPE=release ./build.sh

    # 编译生成的可执行文件和静态库文件分别位于 ../build/release/{bin,lib}

    编译完成之后请试运行其中的例子。比如 bin/inspector_test ,然后通过浏览器访问 http://10.0.0.10:12345/http://10.0.0.10:12345/proc/status,其中 10.0.0.10 替换为你的 Linux box 的 IP。

    例子
    Muduo 附带了几十个小例子,位于 examples 目录。其中包括从 Boost.Asio、JBoss Netty、Python Twisted 等处移植过来的例子。

    examples

    |-- simple # 简单网络协议的实现

    | |-- allinone # 在一个程序里同时实现下面 5 个协议

    | |-- chargen # RFC 864,可测试带宽

    | |-- daytime # RFC 867

    | |-- discard # RFC 863

    | |-- echo # RFC 862

    | |-- time # RFC 868

    | `-- timeclient # time 协议的客户端

    |-- hub # 一个简单的 pub/sub/hub 服务,演示应用级的广播

    |-- roundtrip # 测试两台机器的网络延时与时间差

    |-- asio # 从 Boost.Asio 移植的例子

    | |-- chat # 聊天服务

    | `-- tutorial # 一系列 timers

    |-- netty # 从 JBoss Netty 移植的例子

    | |-- discard # 可用于测试带宽,服务器可多线程运行

    | |-- echo # 可用于测试带宽,服务器可多线程运行

    | `-- uptime # TCP 长连接

    `-- twisted # 从 Python Twisted 移植的例子

    `-- finger # finger01 ~ 07

    基本结构
    Muduo 的目录结构如下。

    muduo

    |-- base # 与网络无关的基础代码,已提前发布

    `-- net # 网络库

    |-- http # 一个简单的可嵌入的 web 服务器

    |-- inspect # 基于以上 web 服务器的“窥探器”,用于报告进程的状态

    `-- poller # poll(2) 和 epoll(4) 两种 IO multiplexing 后端

    Muduo 是基于 Reactor 模式的网络库,其核心是个事件循环 EventLoop,用于响应计时器和 IO 事件。Muduo 采用基于对象(object based)而非面向对象(object oriented)的设计风格,其接口多以 boost::function + boost::bind 表达。

    Muduo 的头文件明确分为客户可见和客户不可见两类。客户可见的为白底,客户不可见的为灰底。

    这里简单介绍各个头文件及 class 的作用,详细的介绍留给以后的博客。

    公开接口
    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 会转移到这个线程,换句话说一个 file descriptor 只能由一个线程读写。TcpConnection 所在的线程由其所属的 EventLoop 决定,这样我们可以很方便地把不同的 TCP 连接放到不同的线程去,也可以把一些 TCP 连接放到一个线程里。TcpConnection 和 EventLoop 是线程安全的,可以跨线程调用。TcpServer 直接支持多线程,它有两种模式:

    1. 单线程,accept 与 TcpConnection 用同一个线程做 IO。

    2. 多线程,accept 与 EventLoop 在同一个线程,另外创建一个 EventLoopThreadPool,新到的连接会按 round-robin 方式分配到线程池中。

    结语
    Muduo 是我对常见网络编程任务的总结,用它我能很容易地编写多线程的 TCP 服务器和客户端。Muduo 是我业余时间的作品,代码估计还有很多 bug,功能也不完善(例如不支持 signal 处理),待日后慢慢改进吧。

    后记:性能测试:

    1. muduo 与 boost asio 吞吐量对比

    2. muduo 与 libevent2 吞吐量对比

    3. 击鼓传花:对比 muduo 与 libevent2 的事件处理效率


    本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/Solstice/archive/2010/08/29/5848547.aspx

    展开全文
  • muduo库安装

    2019-01-10 08:54:45
    Muduo(木铎)是基于 Reactor 模式的网络库。 二、安装 从github库下载源码安装:https://github.com/chenshuo/muduo muduo依赖了很多的库,所以在安装muduo之前应该安装这些库,包括:curl、c-ares、protobuf。 ...

    一、简介

    Muduo(木铎)是基于 Reactor 模式的网络库。

    二、安装

    从github库下载源码安装:https://github.com/chenshuo/muduo

    muduo依赖了很多的库,所以在安装muduo之前应该安装这些库,包括:curl、c-ares、protobuf。

    前面两个在centos6.2可以使用yum安装,protobuf只能源码安装了,参见这篇文章。

    yum install libcurl-devel
    yum install c-ares-devel

    在muduo目录下执行:./build.sh -j2

    中间遇到了一些问题:

    在net/protorpc/RpcChannel.cc文件中NewCallback未定义,以及examples/protobuf/rpc/client.cc文件中NewCallback未定义,最后在github上提了个issue给硕哥,经过他的指导注释了一下CMakfiles的内容,然后编译通过。

    https://github.com/chenshuo/muduo/blob/master/examples/CMakeLists.txt#L39

    https://github.com/chenshuo/muduo/blob/master/muduo/net/CMakeLists.txt#L65

    三、使用

    然后运行test例子:

    展开全文
  • muduo库整体架构简析

    2018-10-14 00:20:24
    muduo是一个高质量的Reactor网络库,采用one loop per thread + thread pool架构实现,代码简洁,逻辑清晰,是学习网络编程的很好的典范。  muduo的代码分为两部分,base和net,base部分实现一些基础功能,例如log...
  • Linux C++ 网络库 Muduo

    2019-09-16 06:37:53
    muduo 是一个基于 Reactor 模式的现代 C++ 网络库,它采用非阻塞 IO 模型,基于事件驱动和回调,原生支持多核多线程,适合编写 Linux 服务端多线程网络应用程序。视频连接:...
  • 一、由来 2010年3月我写了一篇《学之者生,用之者死——ACE历史与简 评》1,其中提到“我心目中理想的网络库”的样子: ·线程安全,原生支持多核多线程。 ·不考虑可移植性,不跨平台,只支持Linux,不支持...
1 2
收藏数 28
精华内容 11
热门标签
关键字:

muduo reactor模式