muduo整体介绍及Echo服务器流程分析

muduo是Ractor模式,整个核心是Reactor;EventLoop就充当了Reactor。下面就是muduo的简化类图结构:

EventLoop是one thread per loop中的loop,每个线程只能有一个EventLoop的实体,它来负责IO和定时器事件的分派。它用eventfd来异步唤醒,不同与传统的用一对pipe。它用TimerQueue作为计时管理,Poller实现IO multiplexing。

Poller是个抽象基类,它实现了pool/epoll的封装。派生类PollPoller实现了poll的封装;派生类EPollPoller实现了epoll的封装。

Channel是selectable IO channel,负责注册与响应IO事件。但是它没有file descriptor,它是TcpConnection、Acceptor、TcpConnection、TimeQueue的成员,其生命周期由后者控制。

Socket是一个RAII handle,封装了一个file descriptor,且在析构时关闭fd。它是Acceptor、TcpConnection的成员,生命周期由后者控制。EventLoop、TimeQueue中拥有fd,但是没有封装为Scokets class。

Connector用来发起TCP连接,它是TcpClient的成员,生命周期由后者控制。

Acceptor用来接收TCP连接,它是TcpServer的成员,生命周期由后者控制。

muduo网络库头文件关系如下:

其中白底为用户可见,灰底为用户不可见。

Edian.h封装了计算机字节顺序/网络字节顺序之间的转换函数,放在命名空间sockets。

SocketsOps.{h, cc}封装了了套接字fd的创建、连接、绑定、监听、关闭函数;还封装了网络地址间的转换,例如“1.2.3.4”/sockaddr_in.sin_addr.s_addr,scokaddr/sockaddr_in等之间的转换。

InetAddress.{h, cc}封装了InetAddress class,类中只有一个私有变量struct sockaddr_in addr_,封装了网络地址的一些操作。resolve实现了域名/主机名解析IP。

Socket.{h, cc}封装了fd,实现了fd常见的一些操作。它使用RAII手法,在析构时close(fd)。

下面以一个Echo服务器为例,讲解一下muduo实现Reactor的大概流程:

Echo源码为muduo自带的,为了便于理解,把封装的EchoServer拆开了。

#include <muduo/base/Logging.h>
#include <muduo/net/TcpServer.h>
#include <muduo/net/EventLoop.h>

#include <boost/bind.hpp>
//define callback function
void onConnection(const muduo::net::TcpConnectionPtr& conn)
{
  LOG_INFO << "EchoServer - " << conn->peerAddress().toIpPort() << " -> "
           << conn->localAddress().toIpPort() << " is "
           << (conn->connected() ? "UP" : "DOWN");
}

void onMessage(const muduo::net::TcpConnectionPtr& conn,
                           muduo::net::Buffer* buf,
                           muduo::Timestamp time)
{
  muduo::string msg(buf->retrieveAllAsString());
  LOG_INFO << conn->name() << " echo " << msg.size() << " bytes, "
           << "data received at " << time.toString();
  conn->send(msg);
}

int main()
{
    LOG_INFO << "pid = " << getpid();
    muduo::net::EventLoop loop;

    muduo::net::InetAddress listenAddr(2007);
    muduo::net::TcpServer server(&loop, listenAddr, "EchoServer");

    server.setConnectionCallback(
            boost::bind(onConnection,  _1));
    server.setMessageCallback(
            boost::bind(onMessage,  _1, _2, _3));

    server.start();
    loop.loop();
    return 0;
}

首先定义了两个callBack函数,这两个函数要有一定格式(传入参数和返回值类型),具体格式定义了Callbacks.h中。onConnection在连接到来时调用,onMessage在消息到来时调用,(具体怎么调用后面解释)。

在main函数首先定了EventLoop对象和TcpServer对象。在定义TcpServer时不仅仅绑定了端口,还传入了EventLoop对象的指针,在TcpServer中保存着EventLoop对象的指针,EventLoop指针只能在TcpServer初始化时指定,后面不能更改。TcpServer在构造函数中还绑定了新连接到来时调用的回调函数,用来处理accept返回的fd(这个绑定其实是Acceptor绑定TcpServer的函数)。

之后,TcpServer对象server设置了回调函数,这两个函数分别在连接建立和消息到达时调用。

调用server.start()时,会初始化server对象中的threadPool_(用来给后面新建连接使用),随后把listen函数放入到loop函数对象容器中(如果在同一个线程则会立即执行,否则在下一次执行完IO事件后执行listen)。listen封装在Acceptor类中,Acceptor在TcpServer创建时创建,也包含了EventLoop对象指针,还包含了channel类。在Acceptor对象初始化时会创建channel类对象且将其加入到EventLoop的监听事件集合中,当有连接到来时,回调函数为void Acceptor::handleRead,在回调函数中,接受新连接,并调用newConnectionCallback_(即TcpServer::newConnection),接收新连接(保存为TcpConnection)并设置新连接回调函数,将新连接加入到另一个EventLoop中,在这个EventLoop中处理接收和发送。

以上大概就是Echo服务器的流程。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-08 17:28:09

muduo整体介绍及Echo服务器流程分析的相关文章

DRF之REST规范介绍及View请求流程分析

编程是数据结构和算法的结合,而在Web类型的App中,我们对于数据的操作请求是通过url来承载的,本文详细介绍了REST规范和CBV规范和CBV请求流程. 编程即数据结构和算法的结合.简单的程序可能不需要跟用户交互数据,但是现代的应用程序几乎都需要跟用户进行交互,不分应用程序类型,不管是CS型还是BS型的程序都是如此,而Python最擅长的Web App即BS型的程序,就是通过url和http来跟用户进行数据交互的,通过url和http请求,用户可以操作服务器端的程序,主要操作分为:增.删.改.

JAVAWEB开发之Struts2详解(一)——Struts2框架介绍与快速入门、流程分析与工具配置以及Struts2的配置以及Action和Result的详细使用

Struts2框架介绍 三大框架:是企业主流JavaEE开发的一套架构.Struts2 + Spring + Hibernate 什么是框架?为什么要学习框架? 框架是实现部分功能的代码(半成品),使用框架简化企业级软件开发. Struts2与MVC? Struts是一款优秀的MVC框架 MVC:是一种思想,是一种模式,将软件分为Model模型.View视图.Controller控制器 JAVAEE软件三层架构:web层(表现层).业务逻辑层.数据持久层(Sun提供javaEE开发规范) Jav

Android bluetooth介绍(四): a2dp connect流程分析

关键词:蓝牙blueZ  A2DP.SINK.sink_connect.sink_disconnect.sink_suspend.sink_resume.sink_is_connected.sink_get_properties.AUDIO.DBUS版本:基于android4.2之前版本 bluez内核:linux/linux3.08系统:android/android4.1.3.4作者:xubin341719(欢迎转载,请注明作者,请尊重版权谢谢)欢迎指正错误,共同学习.共同进步!! Andr

大数据技术之_10_Kafka学习_Kafka概述+Kafka集群部署+Kafka工作流程分析+Kafka API实战+Kafka Producer拦截器+Kafka Streams

第1章 Kafka概述1.1 消息队列1.2 为什么需要消息队列1.3 什么是Kafka1.4 Kafka架构第2章 Kafka集群部署2.1 环境准备2.1.1 集群规划2.1.2 jar包下载2.2 Kafka集群部署2.3 Kafka命令行操作第3章 Kafka工作流程分析3.1 Kafka 生产过程分析3.1.1 写入方式3.1.2 分区(Partition)3.1.3 副本(Replication)3.1.4 写入流程3.2 Broker 保存消息3.2.1 存储方式3.2.2 存储策

第一章、架设服务器前的准备工作 基本架设服务器流程

1.2 基本架设服务器流程 1.2.1 网络服务器成功联机的分析 图 1.2-1.网络联机至服务器所需经过的各项环节 上图显示的是:首先,客户端到服务器的网络要能够通,等到客户端到达服务器后,会先由服务器的防火墙判断该联机能否放行, 等到放行之后才能使用到服务器软件的功能.而该功能又得要通过 SELinux 这个细部权限设定的项目后,才能够读取到文件系统. 但能不能读到文件系统又跟文件系统的权限 (rwx) 有关!上述的每个部分都要能够成功,否则就无法顺利读取数据. 所以,根据上面的流程我们大概

freeswitch呼叫流程分析

今天翻文档时发现之前整理的关于freeswitch呼叫相关的内容,写成博文分享出来也方便我以后查阅. 整体结构图 FreeswitchCore 模块加载过程 freeswitch主程序初始化时会从modules.conf.xml文件中读取配置,如果配置中如下内容生效: <load module="mod_sofia"/> 则执行加载sofia模块操作. 具体过程如下: main switch_core_init_and_modload switch_loadable_mod

Android 4.4KitKat AudioRecord 流程分析

Android是架构分为三层: 底层      Linux Kernel 中间层  主要由C++实现 (Android 60%源码都是C++实现) 应用层  主要由JAVA开发的应用程序 应用程序执行过程大致如下: JAVA应用程序产生操作(播放音乐或停止),然后通过JNI调用进入中间层执行C++代码,中间层处理后可能需要硬件产生动作的,会继续将操作传到Linux Kernel,Kernel ,不需要硬件产生操作的可能在中间层做一些处理就直接返回.需要硬件产生操作的动作则需通过Kernel调用相

Django_Restful Framework之QQ登录流程分析(一)

本篇主要介绍如何使用Django的Restful Framework提供第三方登录的API,主要介绍其流程及基本的代码实现. 在学习之前我们需要知道什么是第三方登录 -- 是指用户可以不在本项目中输入密码,而直接通过第三方的验证,成功登录本项目. 实现第三方登录时,我们需要明确QQ提供的开发者文档,即 : 成为QQ的开发者,注册. 创建应用,即获取本项目对应与QQ互联的应用ID,创建应用 QQ登录开发文档,文档 一.QQ登录流程 有了上述的准备工作,我们需要明确进行第三方登录的流程,这里以QQ登

Sentinel Cluster流程分析

?前面介绍了sentinel-core的流程,提到在进行流控判断时,会判断当前是本地限流,还是集群限流,若是集群模式,则会走另一个分支,这节便对集群模式做分析. 一.基本概念 ?namespace:限流作用于,用于区分一个规则作用于什么范围 ?flowId:代表全局唯一的规则 ID,Sentinel 集群限流服务端通过此 ID 来区分各个规则,因此务必保持全局唯一.一般 flowId 由统一的管控端进行分配,或写入至 DB 时生成. ?thresholdType:代表集群限流阈值模式.其中单机均