Muduo源码分析:TCP服务端和客户端

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()。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值