Muduo采用经典的Reactor架构,支持以线程池的方式实现多线程并发处理。
一、socket通信架构
二、muduo tcp网络架构
话不多说,直接上图
下面,对TCP server和client中用到的主要类进行说明
线程池管理用到的三个类:EventLoopThreadPool、EventLoopThread、Thread
1、 用于创建和管理线程池:EventLoopThreadPool类
(1)EventLoopThreadPool类成员变量
EventLoop* baseLoop_; //指向TcpServer的EventLoop
int numThreads_; //用户指定池内的线程数量
std::vector<std::unique_ptr<EventLoopThread>> threads_; //池内的每个线程对应一个EventLoopThread对象
std::vector<EventLoop*> loops_; //并且每个线程都有一个EventLoop指针,被保存在容器中
(2)EventLoopThreadPool类成员函数
//被TcpServer::start()调用
void EventLoopThreadPool::start();
[1] 为线程池中的每个线程分配一个EventLoopThread对象,并存放在threads_
[2] 每个EventLoopThread对象调用EventLoopThread::startLoop(),并将得到的EventLoop指针存放在loops_
// 为新建连接分配处理线程
EventLoop* EventLoopThreadPool::getNextLoop();
[1] 如果loops_中不为空,则按照RR方法从中取出一个
[2] 如果loops_中为空,则直接返回baseLoop_
2、管理线程:EventLoopThread类
每个线程都有一个EventLoopThread类对象
(1)EventLoopThread类成员变量
EventLoop* loop_; //保存本线程的EventLoop*指针
Thread thread_; //保存本线程
Condition cond_; //封装线程条件变量的操作 pthread_cond_init、pthread_cond_signal等
ThreadInitCallback callback_; //保存线程初始化的回调函数,在TcpServer::setThreadInitCallback()中设置
(2)EventLoopThread类成员函数
构造函数:
[1] 初始化Thread thread_;将EventLoopThread::threadFunc赋值给thread_
[2] 设置回调函数callback_
[3] 初始化cond_
析构函数:
[1] loop_->quit();
[2] thread_.join(); 调用pthread_join()
EventLoop* EventLoopThread::startLoop();
[1] thread_.start(); 创建线程 调用pthread_create()
[2] 循环 while (loop_ == NULL),直到loop不为NULL,退出循环
[3] 线程等待信号 pthread_cond_wait()
void EventLoopThread::threadFunc();
[1] 调用pthread_cond_signal()
[2] loop.loop();
3、封装线程相关的系统API:Thread类
pthread_create()、pthread_join()、pthread_detach()等
4、事件循环:EventLoop类
每个线程都有一个EventLoop类对象
(1)EventLoop类成员变量
const pid_t threadId_; //EventLoop所属的线程的pid
std::unique_ptr<Poller> poller_; //poll or epoll,默认使用epoll。
//EventLoop线程一般被阻塞在poll函数
int wakeupFd_; //用于唤醒功能的文件描述符
std::unique_ptr<Channel> wakeupChannel_; //用于唤醒功能的channel对象
ChannelList activeChannels_; //用于保存发生状态变化的channel对象集合
std::vector<Functor> pendingFunctors_ GUARDED_BY(mutex_); //保存外部注入的回调函数对象,在loop函数中被执行
(2)EventLoop类成员函数
//主线程的EventLoop对象一般是在客户代码中被创建,对应的EventLoop::loop()也是在客户代码中显示调用
构造函数:
[1] poller_:创建new EPollPoller(),查看环境变量如果定义了"MUDUO_USE_POLL",则使用poll,否则使用epoll。
[2] wakeupFd_:创建非阻塞文件描述符用于事件通知 EFD_NONBLOCK | EFD_CLOEXEC
[3] wakeupChannel_:创建new Channel()
void EventLoop::loop();
[1] 轮询,直到调用EventLoop::quit()退出循环
[2] 轮询得到发生状态变化的channel对象集合activeChannels_
[3] 执行每个channel对象的状态处理函数Channel::handleEvent(),处理POLLIN、POLLOUT、POLLERR等
[4] 执行pendingFunctors_容器中的函数,也就是外部注入的回调函数
//通过此接口将外部函数注入到EventLoop::pendingFunctors_容器,最终容器中的函数会被loop()函数调用
void EventLoop::runInLoop(Functor cb);
//Channel::update()会调用此函数,将需要轮询的socket和channel对象注入poller管理器
void EventLoop::updateChannel(Channel* channel);
5、管理服务器监听的socket:Acceptor类
内部管理了Socket类对象和Channel对象
(1)Acceptor类成员变量
EventLoop* loop_; //指向TcpServer的EventLoop对象
Socket acceptSocket_; //用于监听的Socket对象
Channel acceptChannel_; //监听Socket的Channel对象
NewConnectionCallback newConnectionCallback_; //与TcpServer::newConnection()绑定
(2)Acceptor类成员函数
构造函数:
[1] 创建一个用于服务器的监听socket描述符,acceptSocket_
[2] 创建一个channel对象,acceptChannel_
[3] acceptSocket_调用bind()
[4] acceptChannel_设置readCallback_的回调函数 Acceptor::handleRead()
析构函数:
[1] 设置acceptChannel_的events_为空kNoneEvent
[2] remove channel
[3] close(fd)
// 此函数被TcpServer::start()调用
void Acceptor::listen();
[1] 调用系统函数listen(),启动端口监听
[2] 开启channel的可读属性,acceptChannel_.enableReading(),
调用Channel::update() -> EventLoop::updateChannel() ->
EPollPoller::updateChannel() -> EPollPoller::update() 同时更新channel->set_index(kAdded); -> epoll_ctl(EPOLL_CTL_ADD)
// 此函数被注册到Channel::readCallback_
void handleRead();
[1] 调用系统函数accept(),用于接收一个客户端的连接请求
[2] 调用TcpServer::newConnection,用于处理接收到的连接请求
6、Channel类
(1)Channel类成员变量
int index_; //用于Poller类,kNew:-1、kAdded:1、kDeleted:2
7、TCP服务端:TcpServer类
TcpServer:主要有三个成员类 EventLoopThreadPool类、Acceptor类、EventLoop*指针
(1)TcpServer类成员变量
EventLoop* loop_; //主线程的EventLoop对象,它指向用户代码中创建的EventLoop对象,为TcpServer专用,相当于是为主线程提供Loop循环
std::unique_ptr<Acceptor> acceptor_; //Acceptor对象管理监听socket以及对应的channel对象
std::shared_ptr<EventLoopThreadPool> threadPool_; //线程池管理器
ConnectionCallback connectionCallback_; //用户实现回调函数处理新建连接
MessageCallback messageCallback_; //用户实现回调函数处理消息接收
WriteCompleteCallback writeCompleteCallback_;
ThreadInitCallback threadInitCallback_; //保存线程初始化的回调函数,通过void setThreadInitCallback()设置
ConnectionMap connections_; //每个新建连接都对应一个TcpConnection对象,并保存在此容器中,key的格式为name-ipPort#connId
(2)TcpServer类成员函数
构造函数:
[1] 创建并初始化Acceptor对象 acceptor_
[2] 创建EventLoopThreadPool对象 threadPool_
[3] 设置Acceptor的回调函数,把newConnectionCallback_绑定到TcpServer::newConnection()
析构函数:
[1] 对connections_中的每个连接执行销毁
void TcpServer::start();
[1] 启动线程池管理器 threadPool_->start()
[2] 将Acceptor::listen()注入pendingFunctors_容器,loop_->runInLoop()
// 处理监听套接字接收到的新的连接请求,此函数被注册到Acceptor::newConnectionCallback_
void TcpServer::newConnection()
[1] 采用RR方式给新建连接分配EventLoop,threadPool_->getNextLoop()
[2] 创建新的连接 new TcpConnection()
[3] 给新连接创建回调函数setConnectionCallback()、setCloseCallback()、...
[4] 将TcpConnection::connectEstablished()注入pendingFunctors_容器,ioLoop->runInLoop()
// 用于处理连接关闭,被注册到TcpConnection::closeCallback_, 被TcpConnection::handleClose()函数调用
void TcpServer::removeConnection()
[1] 将TcpConnection::removeConnectionInLoop()注入pendingFunctors_容器,loop_->runInLoop()
8、TcpConnection类
TcpConnection类成员函数
构造函数:
[1] 创建socket,new Socket()
[2] 创建channel,new Channel()
[3] 设置channel的回调函数 setReadCallback、setWriteCallback、setCloseCallback、setErrorCallback等
其中readCallback_ = setReadCallback -> TcpConnection::handleRead() -> messageCallback_(),messageCallback_是在TcpServer::setMessageCallback()中设置的。
writeCallback_ = setWriteCallback -> TcpConnection::handleWrite() -> sockets::write()
9、TcpClient类
TcpClient类成员函数
构造函数:
[1] 创建Connector,new Connector()
[2] 设置Connector的回调函数newConnectionCallback_为TcpClient::newConnection()
void TcpClient::connect()
[1] 调用Connector::start()
将Connector::startInLoop注入pendingFunctors_容器,loop_->runInLoop()
// Connector类
void Connector::start()
[1] 将Connector::startInLoop()注入pendingFunctors_容器,loop_->runInLoop(),最终会被EventLoop::loop()调用。
其中void Connector::startInLoop()调用void Connector::connect(),最终调用sockets::connect()。