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

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

分类:muduo源码学习

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拆开了。

muduo/net/TcpServermuduo/net/EventLoopboost/bindonConnection(const muduoconn){ LOG_INFO connconn(conn->connected() ? “UP” : “DOWN”);}conn,muduobuf,muduo::Timestamp time){ muduo::string msg(buf->retrieveAllAsString()); LOG_INFO msgtime.toString(); conn->send(msg);}int main(){LOG_INFO getpid();muduo;muduo::net::InetAddress listenAddr(2007);muduo, listenAddr, “EchoServer”);server.setConnectionCallback(boost::bind(onConnection, _1));server.setMessageCallback(boost::bind(onMessage, _1, _2, _3));server.start();();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服务器的流程。

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

上一篇Memento模式下一篇muduo::EventLoop分析

顶0踩0

你曾经说,你曾经说。走在爱的旅途,我们的脚步多么轻松……

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

相关文章:

你感兴趣的文章:

标签云: