模型

实现流程:

前面已经介绍了EPoller类,EPoller主要监听的是Channel对象,每一个Channel对象会绑定一个文件描述符(fd_),fd_上绑定要监听的事件。当epoll监听到就绪事件时,会将就绪事件添加到激活队列中,激活队列在事件循环(EventLoop的loop中)被循环调用,当激活队列不为空时,依次调用Channel注册的回调。

源码分析

update

update是对上提供的接口,主要调用的是EventLoop类的updateChannel接口将当前对象更新至poller。

void Channel::update()
{addedToLoop_ = true;loop_->updateChannel(this);
}

remove

同理,remove调用的是EventLoop类的removeChannel接口删除当前对象

void Channel::remove()
{assert(isNoneEvent());addedToLoop_ = false;loop_->removeChannel(this);
}

设置回调

void enableReading() { events_ |= kReadEvent; update(); }
void disableReading() { events_ &= ~kReadEvent; update(); }
void enableWriting() { events_ |= kWriteEvent; update(); }
void disableWriting() { events_ &= ~kWriteEvent; update(); }
void disableAll() { events_ = kNoneEvent; update(); }
bool isWriting() const { return events_ & kWriteEvent; }
bool isReading() const { return events_ & kReadEvent; }

什么时候会设置回调?例如上层连接建立成功后,会设置读使能。

void TcpConnection::connectEstablished()
{loop_->assertInLoopThread();assert(state_ == kConnecting);setState(kConnected);channel_->tie(shared_from_this());channel_->enableReading();  // 通道读使能connectionCallback_(shared_from_this());  // 连接回调
}

设置激活事件类型

channel.h中

void set_revents(int revt) { revents_ = revt; }

poller中处理激活队列是会设置通道事件类型,便于Channel处理handleEvent时使用

void PollPoller::fillActiveChannels(int numEvents,ChannelList* activeChannels) const
{for (PollFdList::const_iterator pfd = pollfds_.begin();pfd != pollfds_.end() && numEvents > 0; ++pfd){if (pfd->revents > 0){--numEvents;ChannelMap::const_iterator ch = channels_.find(pfd->fd);assert(ch != channels_.end());Channel* channel = ch->second;assert(channel->fd() == pfd->fd);channel->set_revents(pfd->revents);   // 设置激活通道类型// pfd->revents = 0;activeChannels->push_back(channel);   // 加入激活队列}}
}

handleEvent

处理激活的Channel事件,由Poller更新激活的Channel列表,EventLoop::loop()根据激活Channel列表,逐个执行Channel中已注册好的相应回调。

void Channel::tie(const std::shared_ptr<void>& obj)
{tie_ = obj;     // std::shared_ptr是强引用的智能指针, 可以直接赋值给tie_tied_ = true;   // 设置绑定标志
}void Channel::handleEvent(Timestamp receiveTime)
{std::shared_ptr<void> guard;if (tied_){guard = tie_.lock();   // weak_ptr::lock可将weak_ptr提升为shared_ptrif (guard)             // 通过非空判断可以确定guard是否存在{handleEventWithGuard(receiveTime);}}else{handleEventWithGuard(receiveTime);}
}void Channel::handleEventWithGuard(Timestamp receiveTime)
{eventHandling_ = true;LOG_TRACE << reventsToString();if ((revents_ & POLLHUP) && !(revents_ & POLLIN)){if (logHup_){LOG_WARN << "fd = " << fd_ << " Channel::handle_event() POLLHUP";}if (closeCallback_) closeCallback_();}if (revents_ & POLLNVAL){LOG_WARN << "fd = " << fd_ << " Channel::handle_event() POLLNVAL";}// 根据不同的事件类型, 执行不同的回调    if (revents_ & (POLLERR | POLLNVAL)){if (errorCallback_) errorCallback_();}if (revents_ & (POLLIN | POLLPRI | POLLRDHUP)){if (readCallback_) readCallback_(receiveTime);}if (revents_ & POLLOUT){if (writeCallback_) writeCallback_();}eventHandling_ = false;
}

tie_对象

tie_是一个使用std::weak_ptr维护的对象,目的是为了解决循环引用的问题。关于循环引用的问题,可以参考:https://blog.csdn.net/www_dong/category_10702918.html?spm=1001.2014.3001.5482

定义:

std::weak_ptr<void> tie_;

TcpConnection建立连接成功的时候调用tie将自身指针传给Channel。

void TcpConnection::connectEstablished()
{loop_->assertInLoopThread();assert(state_ == kConnecting);setState(kConnected);channel_->tie(shared_from_this());  // 绑定当前对象, shared_from_this()主要是为了解决TcpConnection先于Channel被析构情况可能带来的问题channel_->enableReading();connectionCallback_(shared_from_this());
}

关于shared_from_this,可以参考:https://blog.csdn.net/www_dong/article/details/111999624

muduo网络库——Channel相关推荐

  1. muduo网络库学习(八)事件驱动循环线程池EventLoopThreadPool

    muduo是支持多线程的网络库,在muduo网络库学习(七)用于创建服务器的类TcpServer中也提及了TcpServer中有一个事件驱动循环线程池,线程池中存在大量线程,每个线程运行一个Event ...

  2. muduo网络库学习(七)用于创建服务器的类TcpServer

    目前为止,涉及到的绝大多数操作都没有提及线程,EventLoop,Poller,Channel,Acceptor,TcpConnection,这些对象的执行都是在单独线程完成,并没有设计多线程的创建销 ...

  3. muduo网络库学习(四)事件驱动循环EventLoop

    muduo的设计采用高并发服务器框架中的one loop per thread模式,即一个线程一个事件循环. 这里的loop,其实就是muduo中的EventLoop,所以到目前为止,不管是Polle ...

  4. muduo网络库源码阅读Step by Step

    Posted on: Nov 26 2015 Categories: muduo C++ Tags: muduo 一般写服务端程序都需要有一个称手的网络库来帮我们处理琐碎的网络通信细节,比如连接的建立 ...

  5. 基于C++11的muduo网络库

    文章目录 写在前面 项目编译问题 库安装的问题 项目测试代码 关于压力测试 项目概述 muduo网络库的reactor模型 muduo的设计 muduo各个类 辅助类 NonCopyable Time ...

  6. muduo网络库的封装

    一.基础socket编程 网络编程的底层离不开socket,其处理流程表示如下: int sockfd = socket(AF_INET, SOCK_STREAM, 0);struct sockadd ...

  7. muduo网络库浅谈(一)

    muduo网络库浅谈(一) 序言 第一章 muduo的关键结构 class EventLoop class Channel class Poller 番外 定时任务 class Timestamp c ...

  8. Muduo网络库核心梳理

    Muduo网络库 Muduo网络库本身并不复杂,是一个新手入门C++面向对象网络编程的经典实战项目.但是,新手在刚刚上手读代码的时候,非常容易陷入代码的汪洋大海,迷失方向.本文旨在简要梳理Muduo网 ...

  9. muduo网络库学习总结:基本架构及流程分析

    muduo网络库学习:基本架构及流程分析 基本架构 Basic Reactor Mutiple Reactor + ThreadPool muduo库的基本使用 基本结构介绍 EventLoop类 P ...

最新文章

  1. python --time()函数
  2. bigdecimal 和负数比较_Java中BigDecimal精度和相等比较的坑
  3. 谷歌浏览器 关闭 提示恢复网页功能_最强浏览器又更新喽!
  4. (转)iOS里面Frameworks介绍
  5. java map 变量_Java源码解析HashMap成员变量
  6. 红皮书--With语句及布尔型
  7. mysql 性能问题_mysql 性能问题
  8. 关于3Q大战和反垄断
  9. 浅谈浏览器端JavaScript跨域解决方法
  10. 用c语言编写一个简易计算器
  11. 基于JavaEE的学生信息管理(选课)系统论文
  12. 使用Robotframework-ride,导入Selenium2Library库后缺少“Open Browser”关键字
  13. 创翼linux版本,创翼电信客户端for Mac-创翼客户端Mac版下载 V1.3.7-PC6苹果网
  14. 【畅购商城】 B2B、 C2C、B2C、C2B、O2O、B2B2C电商模式介绍与分析
  15. c语言小鱼的游泳时间,小鱼系列简单题参考代码
  16. 用python模拟一个文本浏览器来抓取网页
  17. OpenCV实验(7):人脸面部识别
  18. 苹果公司邮箱联系大全
  19. mysql语句总结_mysql语句总结
  20. 关于征集参与团体标准起草单位的通知的各地奖励政策汇总

热门文章

  1. Postgresql监控插件pg_stat_statements的安装
  2. [出海创投] 新加坡无人零售路径逐渐清晰
  3. MySQL SQL 优化参数 引发的悲剧
  4. ProtocolBuffer在Swift中实践记录
  5. 蓝牙耳机连接电脑后再连接手机接听电话没有声音
  6. 配置SSM环境---上
  7. java卸载vsftp_Ubuntu下vsftp安装和配置
  8. 使用Excel导出XML格式文件
  9. Linux下DDNS客户端的使用
  10. 改造analysis-dynamic-synonym源码访问远程数据库