0
点赞
收藏
分享

微信扫一扫

muduo各个类梳理


文章目录

  • ​​一、Channel类​​
  • ​​二、Poller/EpollPoller类​​
  • ​​三、EventLoop类​​
  • ​​四、Thread、EventLoopThread、EventLoopThreadPool类​​
  • ​​五、Acceptor类​​
  • ​​六、Buffer类​​
  • ​​七、TcpConnection类​​
  • ​​八、TcpServer类​​

muduo各个类梳理_网络编程


mainReactor就是我们代码中的mainloop(baseloop),subReactor是我们代码中的工作线程进行读写事件的处理,read是底层做的,decode、compute、encode是用户做的。从网络上read数据,然后从网络上send数据,这些是由muduo库的。decode、compute、encode是用户在OnMessage处理的业务逻辑,每一个线程执行一个独立的Reactor

muduo库的核心模块包括:Channel、Poller/EpollPoller、EventLoop、Thread、EventLoopThread、EventLoopThreadPool、Socket、Acceptor、Buffer、TcpConnection、TcpServer

一、Channel类

muduo各个类梳理_网络库_02

Channel主要是封装了以下成员:

  • fd_:需要注册在Poller(poll/epoll)的用于和用户通信的文件描述符
  • events_:fd感兴趣的事件
  • revents_:fd发生的事件
  • loop_:Channel归属的事件循环EventLoop
  • callback_:发生事件时,根据Poller通知的revents执行的回调函数
  • index_:用于标识Chnnel的状态

muduo各个类梳理_网络库_03


我们总共只有两种Channel(acceptorChannel和connChannel),因为总共只有两种fd,分别是用于监听新用户连接的listenfd和用于监听已连接用户读写事件的connfd

二、Poller/EpollPoller类

相当于是事件分发器Demultiplex

muduo各个类梳理_muduo_04


Poller封装了以下成员:

  • channels_:一个事件循环EventLoop中包含一个Poller,这个Poller负责管理channels_,负责监听这些channels_上的事件,有事件发生时,会把有事件发生的Channel放入EventLoop::activateChannels_,然后ownerLoop_通过activateChannels_调用处理事件的回调。Channel和Poller不能直接通信,通过EventLoop通信
  • ownerLoop_:Poller所属的EventLoop,Poller会填充有事件发生的Channel到ownerLoop_的成员到activateChannels_

void EventLoop::loop(){
looping_ = true;
quit_ = false;

LOG_INFO("EventLoop %p start looping \n", this);

while(!quit_){
activateChannels_.clear();
pollReturnTime_ = poller_->poll(kPollTimeMs, &activateChannels_);
// for循环处理所有发生事件的channel
for(Channel* channel : activateChannels_){
// poller监听哪些channel发生事件,然后上报给EventLoop,EventLoop通知channel调用相应的回调函数处理相应的事件(Channel执行回调)
channel->handleEvent(pollReturnTime_);
}
// subReactor给唤醒后,执行需要处理的回调操作(mainReactor事先注册的),接收新用户的Channel
doPendingFunctors();
}

LOG_INFO("EventLoop %p stop loop \n", this);
looping_ = false;
}

三、EventLoop类

muduo各个类梳理_数据_05

  • activateChannels_:包含了所有发生事件的Channel,Poller会把有事件发生的Channel放入EventLoop::activateChannels
  • wakeupFd_和wakeupChannel_:一个wakeupFd_隶属于一个EventLoop,每一个wakeupFd_都是注册在了EventLoop管理的Poller上。对于subloop来说,wakeupChannel_用于和mainloop通信,activateChannels用于已连接的客户端通信,如果activateChannels没有事件发生,subloop就会一直阻塞监听,而此时有新的客户连接,mainloop需要找一个subloop处理这个已连接用户的读写事件,就需要往这个subloop的wakeupFd_上写8字节数据唤醒
  • pendingFunctors_:每一个回调函数都需要在发生事件的EventLoop所属的线程执行,如果当前loop是属于当前执行的线程,那直接执行回调函数,否则就把回调函数存到pendingFunctors这个vector里面,然后唤醒相应loop所在线程。然后被唤醒的线程会执行在pendingFunctor里所有的函数

muduo各个类梳理_c++_06

四、Thread、EventLoopThread、EventLoopThreadPool类

EventLoopThreadPool类的成员如下:

muduo各个类梳理_数据_07


getNextLoop方法:通过轮询算法获取下一个subloop,如果用户没有使用setThreadNum设置subloop线程的数量,那就没有创建subloop,getNextLoop返回的一直是baseloopEventLoopThread类的成员如下:

muduo各个类梳理_网络编程_08


EventLoopThread封装了线程Thread以及对应的事件循环EventLoop,Thread封装了std::threadThread类的成员如下:

muduo各个类梳理_网络库_09


TcpServer启动的时候,会让自己的成员threadPool_也启动

muduo各个类梳理_网络库_10


线程池启动时,会创建事件循环线程EventLoopThread,让该EventLoopThread调用startLoop方法

muduo各个类梳理_muduo_11


接着会让事件循环对应的Thread类线程启动

muduo各个类梳理_网络库_12


这里的thread_.start方法就会调用thread_生成时传入的回调函数,即EventLoopThread::threadFunc

muduo各个类梳理_c++_13


这样就启动了事件循环,即epoll_wait开始监听事件

五、Acceptor类

muduo各个类梳理_muduo_14

  • loop_:Acceptor所属的事件循环,即mainLoop
  • acceptSocket_、acceptChannel_:封装了listenfd,用于监听新用户连接

Acceptor工作在mainLoop,主要封装了listenfd相关操作,包括创建socket、bind、listen

六、Buffer类

Buffer类的成员如下:

muduo各个类梳理_muduo_15

缓冲区里有kCheapPrepend、readeridx、writeridx,这3个成员,[readeridx, writeridx]表示可读数据区间

prependable有8个字节,是头部信息,用于记录数据包的长度,刚开始readeridx和writeridx都在这8个字节处的位置,然后我们写数据进去,写好的东西就可以是待发送的东西,由Buffer专门进行在缓冲区读取数据进行发送,我们从缓冲区可以进行send发送,用户也可以不断从缓冲区读取数据,通过readeridx和writeridx处理

Buffer是缓冲区,对于nonblocking(非阻塞)的I/O,我们都需要设置缓冲区,涉及到应用写数据写到缓冲区,write函数将应用程序缓冲区的数据再写到TCP的发送缓冲区,最后发送数据

如果应用程序调用write直接写入TCP的发送缓冲区,写满了就要发送,应用程序就要暂停写入等待发送完成,这是同步的过程,效率比较慢。 如果有缓冲区的话,应用程序可以随意的向应用程序缓冲区写数据,等TCP缓冲区空了Buffer再将应用程序缓冲区中的数据写入TCP缓冲区

应用产生数据快,tcp发送的慢,难道每一次发送数据都要等tcp发送完上一次的数据再发送当前数据?

写数据到Buffer,然后让系统去调用write从Buffer写入TCP发送缓冲区,或者系统调用read从TCP接收缓冲区写入Buffer。相当于应用发送或者接收数据和tcp真实发送或者接收数据就成异步的了,这样非常高效

七、TcpConnection类

muduo各个类梳理_muduo_16


封装了socket,Channel,和一系列回调操作,高水位线的控制(不要发送过快),发送和接收缓冲区

对于Channel执行的回调,都是由TcpConnection来设置的

八、TcpServer类

muduo各个类梳理_数据_17

muduo各个类梳理_muduo_18


举报

相关推荐

0 条评论