Muduo是由陈硕大佬个人开发的C++网络库,最近在剖析其源码,在此做一些归纳整理。
Channel模块
内含向Poller中注册的文件描述符fd,封装了感兴趣的事件events、Poller返回的发生的事件revents,和一组能够根据fd发生的事件revents进行回调的回调函数callbacks
共有两种Channel,一种是listenfd - acceptorChannel,一种是connfd - connectionChannel
Poller和EPollPoller - Demultiplex
std::unordered_map<int, Channel*> channels_; // key为fd
通过epollctl把Channel中包含的fd注册到epoll上,当epoll返回时,可以通过fd找到Channel,进而进行相应的回调。
EventLoop - Reactor
std::vector<Channel *> activeChannels_;
std::unique_ptr<Poller> poller_;
一个Eventloop管理一堆Channel和一个poller。Channel想注册到poller上或者在poller上修改自己感兴趣的事件,Channel都是通过EventLoop来获取到poller,进而完成相应任务;同时,poller监听到sockfd有相应事件发生,也要通过EventLoop来调用相应Channel的fd的所发生事件的回调函数。
int wakeupFd_; // 一个wakeupfd隶属于一个loop
std::unique_ptr<Channel> wakeupChannel_;
loop执行的时候,驱动底层的事件分发器Demultiplx也即epoll_wait,若没有事件发送,则loop一定阻塞在epoll_wait上;若是想唤醒某个loop的阻塞状态,那就可以通过loop对象获取其对应的wakeupfd,并往wakeupfd写一点数据,来使loop从epoll_wait上返回,这是因为每一个wakeupfd也封装成了一个wakeupChannel,注册在了底层的epoll上。
std::vector<Functor> pendingFunctors_;
如果当前线程要调用其他线程中的loop进行回调操作,则将回调函数存放到pendingFunctors_中,并weakup相应的loop。
Thread、EventLoopThread和EventLoopThreadPool
EventLoop *getNextLoop();
通过轮询算法获取下一个subLoop,如果没有setThreadNum设置多线程,那么获取到的永远是baseLoop;如果有设置过多线程,那么threadPool会驱动底层创建新线程,一个thread对应一个loop,即 one loop per thread
Socket、Acceptor
主要封装了listenfd相关操作,socket创建、bind、listen,listen开启后打包成acceptorChannel,放到baseLoop去执行
Buffer
缓冲区 应用写数据 =》缓冲区 =》 Tcp发送缓冲区 =》 send
+-------------------+------------------+------------------+
| prependable bytes | readable bytes | writable bytes |
| 缓冲区头 | (CONTENT) | 可写空间 |
+-------------------+------------------+------------------+
| | | |
0 <= readerIndex <= writerIndex <= size
TcpConnection
一个连接成功的客户端对应一个TcpConnection,封装了Socket、Channel和各种回调函数,还有发送和接收缓冲区
TcpServer
封装Acceptor,EventLoopThreadPool,以及
std::unordered_map<std::string, TcpConnectionPtr> connections_;