muduo库源码剖析(二) 服务端
一. TcpServer类:
管理所有的TCP客户连接,TcpServer供用户直接使用,生命期由用户直接控制。用户只需设置好相应的回调函数(如消息处理messageCallback)然后TcpServer::start()即可。
主要数据成员:
boost::scoped_ptr<Accepter> acceptor_; 用来接受连接
std::map<string,TcpConnectionPtr> connections_; 用来存储所有连接
connectonCallback_,messageCallback_,writeCompleteCallback_,用来接受用户注册的回调函数
EventLoop* loop; 接受连接的事件循环
主要功能函数:
set*Callbak() 注册用户回调函数
newconnection() 需要在构造函数内将其注册给Acceptor,当Acceptor接受一个连接之后回调该函数。在本函数内部新建一个connection对象,并将 *Callback_注册给新建的 Connection 对象。最后,从线程池取出一个线程做I/O线程,在该I/O线程的 EventLoop 的 runInLoop() 中传入 TcpConnection::connectEstablished(). 因为必然不在一个线程中,在runInLoop()中调用EventLoop::quueInLoop(),将TcpConnection::connectEstablished()加入pendingFunctors.
二. Acceptor类:
负责监听连接请求,接收连接并将新的连接返回给TcpServer。
Acceptor主要是供TcpServer使用的,其生命期由后者控制。一个Acceptor相当于持有服务端的一个listenning socket描述符,该socket可以accept多个TCP客户连接,。
主要数据成员:
EventLoop* loop_;
Socket acceptSocket_;封装了socket等,用来监听
Channel acceptChannel_;Acceptor通过Channel向Poller注册事件,EventLoop通过Channel分发回调Acceptor相应的事件处理函数。
boost::function<void(sockfd,InetAddress&)>NewConnectionCallback_ , 连接请求接收之后,通过其回调TcpServer::newconnection().
主要功能函数:
listen(),调用Socket::listen()开始监听,同时,调用Channel::enableReading()向Poller注册可读事件,有数据可读代表新来了连接请求。
handleRead(),在构造函数中将其注册给Channel::readCallback_。当Poller发现属于Acceptor的Channel的可读事件时,在EventLoop中会驱动Channel::handleEvent()-->Channel::handleEventWithGuard()进行事件分发,调用readCallback回调 Acceptor::handlRead(),在其内调用Socekt::accept(),再回调TcpServer::newconnection(),将新连接的sockfd传回给TcpServer。
服务端监听及接受连接的流程:
向Poller注册监听事件的主线调用流程,TcpServer::start()-->EventLoop::runInLoop(Acceptor::listen())-->Channel::enableReading()-->Channel::update(this)-->EventLoop::updateChannel(Channel*)-->Poller::updateChannel(Channel*)
接受连接,当Poller::poll()发现有事件就绪,通过 Poller::fillActiveChannel() 将就绪事件对应的 Channel 加入 ActiveChannelList,
EventLoop::loop()-->Poller::poll()-->Poller::fillActiveChannel(),loop()-->Channel::handleEvent()->Acceptor::handleRead()->TcpServer::newConnection()->EventLoop::runInLoop(bind(&TcpConnection::connectEstablished))->EventLoop::queueInLoop()->EventLoop::loop()->EventLoop::doPendingFunctors()->TcpConnection::connectEstablished()。
三. Connection类:
用于管理一个具体的TCP客户连接,完成用户指定的连接回调connectionCallback。
TcpConnection构造时接收参数有TCP连接的描述符sockfd,服务端地址localAddr,客户端地址peerAddr,并通过Socket封装sockfd。且采用Channel管理该sockfd,
主要数据成员:
enum StateE { kDisconnected, kConnecting, kConnected, kDisconnecting };分别表示已断开,正在连接,已连接,正在断开。
scoped_ptr<Socket> socket_;封装该连接的socket
scoped_ptr<Channel> channel_;连接可以通过该channel向Poller注册该连接的读写等事件。连接还要向Channel注册TcpConection的可读/可写/关闭/出错系列回调函数,用于Poller返回就绪事件后Channel::handleEvent()执行相应事件的回调。
boost::function<void()> **Callback_,在TcpServer::newconnection()中创建TcpConnection时,就会将TcpServer中的各种处理函数注册给相应的 TcpConnection::*Callback_ 。
Buffer inputBuffer_,outputBuffer_。输入输出的缓冲。
主要功能函数:
handle{Read(),Write(),Close(),Error()},处理连接的各种事件,会由Channel::handleEvent()根据Poller返回的具体就绪事件分发调用相应的TcpConnection::handle**().
connectEstablished(),设置连接的状态为kConnected,将channel_进行绑定,调用channel::enableReading()向Poller注册读事件,最后回调connectionCallback_会回调TcpServer中相应的回调函数,一般会在TcpServer中继续回调用户传进来的回调函数。
send(),sendInLoop(),send()有几个重载都是进行发生数据,send()-->sendInLoop(),后者中检测输出buffer中没有数据排队就直接写,如果没有写完,或者outbuffer中有数据排队则将数据追加到outbuffer中,然后调用channel::enableWriting()向Poller注册写事件。
TcpConnection::setTcpNoDelay()->socketopt(..,TCP_NODELAY..)来关闭Nagle算法。
发送数据流程:
TcpConnection::send(string& message)->EventLoop::runInLoop(bind(&TcpConnection::sendInLoop(string& message))->EventLoop::doPendingFunctors()->TcpConnection::sendInLoop(string& message)保证消息发送的线程安全,后者通过write系统调用发送消息。
当Poller返回一个连接的可写或者可读就绪事件时,回调过程类似Acceptor的连接接受过程。
muduo库源码剖析(二) 服务端的更多相关文章
- muduo库源码剖析(一) reactor模式
一. Reactor模式简介 Reactor释义“反应堆”,是一种事件驱动机制.和普通函数调用的不同之处在于:应用程序不是主动的调用某个API完成处理,而是恰恰相反,Reactor逆置了事件处理流程, ...
- zookeeper源码分析之五服务端(集群leader)处理请求流程
leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...
- zookeeper源码分析之四服务端(单机)处理请求流程
上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...
- Netty 4源码解析:服务端启动
Netty 4源码解析:服务端启动 1.基础知识 1.1 Netty 4示例 因为Netty 5还处于测试版,所以选择了目前比较稳定的Netty 4作为学习对象.而且5.0的变化也不像4.0这么大,好 ...
- Netty源码剖析-关闭服务
参考文献:极客时间傅健老师的<Netty源码剖析与实战>Talk is cheap.show me the code! ----主线: ----源码: 先在服务端加个断点和修改下代码:如 ...
- Netty源码剖析-启动服务
参考文献:极客时间傅健老师的<Netty源码剖析与实战>Talk is cheap.show me the code! --1主线分两步: 一:首先在our thread里,如果写在mai ...
- Django Rest Framework源码剖析(二)-----权限
一.简介 在上一篇博客中已经介绍了django rest framework 对于认证的源码流程,以及实现过程,当用户经过认证之后下一步就是涉及到权限的问题.比如订单的业务只能VIP才能查看,所以这时 ...
- Qt信号槽源码剖析(二)
大家好,我是IT文艺男,来自一线大厂的一线程序员 上节视频给大家讲解了Qt信号槽的基本概念.元对象编译器.示例代码以及Qt宏:今天接着深入分析,进入Qt信号槽源码剖析系列的第二节视频. Qt信号槽的宏 ...
- Nacos(二)源码分析Nacos服务端注册示例流程
上回我们讲解了客户端配置好nacos后,是如何进行注册到服务器的,那我们今天来讲解一下服务器端接收到注册实例请求后会做怎么样的处理. 首先还是把博主画的源码分析图例发一下,让大家对整个流程有一个大概的 ...
随机推荐
- "高可用方案工具包" high availability toolkit 1.1
"高可用方案工具包" high availability toolkit 1.1 公布了. version 1.1 新增了gossip protocol 的高可用HA方案应用. 项 ...
- POJ3414 Pots
题目: 给你两个容器,分别能装下A升水和B升水,并且可以进行以下操作 FILL(i) 将第i个容器从水龙头里装满(1 ≤ i ≤ 2); DROP(i) 将第i个容器抽干 ...
- winFrom线程
方法--->委托--->BeginInvoke用指定的参数异步执行委托 委托就是我想做什么,而你可以作什么,我就让你去做.
- (转载)Android常用的Dialog对话框用法
Android常用的Dialog对话框用法 Android的版本有很多通常开发的时候对话框大多数使用自定义或是 Google提供的V4, V7 兼容包来开发保持各个版本的对话框样式统一,所以这里使用的 ...
- 使用Flask和Bootstrap构建博客系统(1) - 准备篇
技术栈 macOS10.12.5 Python2.7.13 Bootstrap4.0.0-beta.2 virtualenv virtualenvwrapper 安装Python2.7.13 下载Bo ...
- PCL:全程详解 VS2010+PCL配置
浑浑噩噩半年时间,终于不得不干点和机器人有关的东西.ICRA和IROS推荐的三维图形库-点云库,几乎成了机器人视觉算法的标配. 参考了几篇文章,最后终于配置成功. 下面是文章地址: 这个有点看头,累积 ...
- RabbitMQ学习之集群镜像模式配置
1.增加负载均衡器 关于负载均衡器,商业的比如F5的BIG-IP,Radware的AppDirector,是硬件架构的产品,可以实现很高的处理能力.但这些产品昂贵的价格会让人止步,所以我们还有软件负载 ...
- 自定义View实现圆角化
目的: 1.实现自定义ReleativeLayout圆角化 实现: 1.在res目录中新建attrs.xml文件,自定义属性如下. <?xml version="1.0" e ...
- 【udacity】机器学习-2模型验证
Evernote Export 1.模型的评估与验证简介 机器学习通常是大量传入数据,然后会有一些关于数据的决策.想法和摘要. 2.模型评估 评估模型使用的是各种数据分析的方法,至少需要使用pytho ...
- 浅谈[^>]在正则中的2种用法
/^A/会匹配"An e"中的A,但是不会匹配"ab A"中的A,此时^A的意思是“匹配开头的A” /[^a-z\s]/会匹配"my 3 sister ...