muduo网络库脉络分析(2)

muduo网络库脉络分析(1) 去年看muduo网络库时没有总结博文,导致前段时间用muduo时发现好多东西都模模糊糊,于是就花时间又一次翻阅了muduo源码,并用此篇博文记录下其网络库整体脉络,以便是后来者入手起来更方便,同时也可用作自己以后复习的资料1.如何入手muduo库其实在这之前也没有尝试去分析一个网络库的总脉络,更没有去尝试把它以博文的形式总结下来。那么我们该如何尝试去分析这样一个网络库的整体脉络呢?其实我有想过将mu 阅读详情

因为此篇博文是上篇博文的延续,所以读者在阅读此时最好能先去看一下muduo网络库脉络分析(1)

Channel类

其实在上篇博文讲完Acceptor类之后,我因该按照流程顺序接着讲TcpConnection类的,但是因为TcpConnection中包含一个很重要的类Channel类,之前讲时也都有设计Channel类,但是我只是笼统的描述那是对事件的一个抽象,所以这里将Channel类,既可以帮助大家理解前面的内容,同时也使我在将之后的TcpConnection类时能够得心应手
Channel类的定义

  EventLoop* loop_;
  const int  fd_;
  int        events_;
  int        revents_; 
  ReadEventCallback readCallback_;
  EventCallback writeCallback_;
  EventCallback closeCallback_;
  EventCallback errorCallback_;

一个具有事件分发功能的类,最起码得拥有的数据成员有,分发哪个文件描述符上的事件即上面数据成员中的fd_,其次得知道该poller监控该文件描述符上的哪些事件,对应events_,接着就是当该文件描述符就绪之后其上发生了哪些事件对应上面的revents。知道了发生了什么事件,要达到事件分发的功能你总得有各个事件的处理回调函数把,对应上面的各种callback。最后该Channel由哪个loop_监控并处理的loop_

Channel提供的主要接口

//该接口便是Channel最核心的接口真正实现事件分发的函数
void handleEvent(Timestamp receiveTime);
//以下接口便是设置各种事件对应的回调函数
void setReadCallback(const ReadEventCallback& cb);
void setWriteCallback(const EventCallback& cb);
void setCloseCallback(const EventCallback& cb);
void setErrorCallback(const EventCallback& cb);
//该接口用来设置Poller需要监听Channel的哪些事件
 void set_revents(int revt);

为了让读者更加清楚Channel的核心接口做了什么,这里简单的贴以下其源码

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;
}

Channel的核心事件分发接口为handleEvent其调用了上面的handleEventWithGuard接口,其内部我相信写过I/O复用的读者一看便会知道它都干了些什么

(4)TcpConnection类

中途小插曲Channel类叙述完了,那我们就接着上篇博文讲,muduo会将和新连接相关的所有内容统一封装到TcpConnection中
TcpConnection主要数据成员定义如下

  EventLoop* loop_;
  boost::scoped_ptr<Socket> socket_;
  boost::scoped_ptr<Channel> channel_;
  ConnectionCallback connectionCallback_;
  MessageCallback messageCallback_;
  WriteCompleteCallback writeCompleteCallback_;
  HighWaterMarkCallback highWaterMarkCallback_;
  CloseCallback closeCallback_;
  Buffer inputBuffer_;
  Buffer outputBuffer_; 

(1)标示一个连接最重要的当然是对应的套接字,上述定义了socket_(对套接字的封装)成员变量
(2)套接字有了其上对应的事件以及处理都将由和套接字对应的Channel来处理,其对应的变量为channel_
(3)由用户传入的各种回调
(4)每一个连接多会对应一对读写buffer对应上面的inputBuffer_和outputBuffer_(关于应用层buffer在网络库中的重要性请翻阅我之前的文章)
(5)每个连接所属的loop循环对应loop_

TcpConnection中提供的主要接口

//给连接发送数据的接口
void send(const StringPiece& message);
//关闭该连接写端的接口
void shutdown();
//强制关闭该连接的接口
void forceClose();
//以下接口为设置连接对应的各种回调
void setConnectionCallback(const ConnectionCallback& cb);
void setMessageCallback(const MessageCallback& cb);
void setWriteCompleteCallback(const WriteCompleteCallback& cb);
void setHighWaterMarkCallback(const HighWaterMarkCallback& cb, size_t highWaterMark);
void setCloseCallback(const CloseCallback& cb);

TcpConnection对外提供的主要接口如上并不复杂,复杂的是其内部实现的各种事件处理函数,所以读者要想明白muduo库是如何处理可读,可写,关闭等事件,需自己去看一下下面几个TcpConnection的私有成员函数

//处理读事件
void handleRead(Timestamp receiveTime);
//处理写事件
void handleWrite();
//处理关闭事件
void handleClose();
//处理错误事件
void handleError();

需要强调的一点是这些处理函数都是要传给TcpConnection对应的Channel的

关于TcpConnection类还有值得强调的一点就是

enum StateE { kDisconnected, kConnecting, kConnected, kDisconnecting };

上面枚举了每个TcpConnection对应的几种状态,可别小看这东西,他们可是muduo用于处理服务器中过期事件的常见问题的关键所在

(5)EventLoopThreadPool类

muduo的TcpServer类通过该类创建多个线程,且每个线程上都运行这一个loop循环
EventLoopThreadPool主要数据成员

  int numThreads_;
  int next_;
  boost::ptr_vector<EventLoopThread> threads_;
  std::vector<EventLoop*> loops_;

(1)创建多少个loop线程 对应成员numThreads_
(2)loops_用来保存每个loop循环的EventLoop的指针
(3)next为保存当前loops_的下标
(5)threads_保存运行loop循环的线程

EventLoopThreadPool提供的接口

//设置开启loop循环的线程数量
void setThreadNum(int numThreads);
//启动各个loop线程
void start(const ThreadInitCallback& cb = ThreadInitCallback());
//获得loops_中的下一个EventLoop地址
EventLoop* getNextLoop();

3.总结

到此位置我已从外到内的把muduo库中最核心的几个类一一介绍完了,此时我们可以再次回到最外层的TcpServer类看一看。其中有一个newConnection的私有成员函数,该函数是传给其成员变量acceptor_的新连接回调,即当baseloop中监听到有新连接到来时,会通过此回调处理新连接,那么它是咋么处理新连接的呢?
newConnection源码

void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr)
{
  loop_->assertInLoopThread();
  EventLoop* ioLoop = threadPool_->getNextLoop();
  char buf[64];
  snprintf(buf, sizeof buf, "-%s#%d", ipPort_.c_str(), nextConnId_);
  ++nextConnId_;
  string connName = name_ + buf;

  LOG_INFO << "TcpServer::newConnection [" << name_
           << "] - new connection [" << connName
           << "] from " << peerAddr.toIpPort();
  InetAddress localAddr(sockets::getLocalAddr(sockfd));
  // FIXME poll with zero timeout to double confirm the new connection
  // FIXME use make_shared if necessary
  TcpConnectionPtr conn(new TcpConnection(ioLoop,
                                          connName,
                                          sockfd,
                                          localAddr,
                                          peerAddr));
  connections_[connName] = conn;
  conn->setConnectionCallback(connectionCallback_);
  conn->setMessageCallback(messageCallback_);
  conn->setWriteCompleteCallback(writeCompleteCallback_);
  conn->setCloseCallback(
      boost::bind(&TcpServer::removeConnection, this, _1)); // FIXME: unsafe
  ioLoop->runInLoop(boost::bind(&TcpConnection::connectEstablished, conn));
}

我们可以看到每次获得新连接的套接字后,newConnection会先调用threadPool_->getNextLoop()来轮流获得各个线程中的EventLoop循环,然后在构造新的TcpConnection时会将此EventLoop的地址传给该新连接对象,以此种方式来平均的将各个连接分配给各个loop循环,这就是muduo采取的多线程负载均衡的策略

GMSL2摄像头接入避坑指南:从FMC子卡配置到V4L2调用的完整流程(附Ubuntu20.04实测) 本文详细解析了GMSL2摄像头接入的全流程,从FMC子卡配置到V4L2调用的完整指南。基于XC7Z100平台实测经验,提供了硬件选型、带宽优化、Linux驱动配置及高分辨率采集的实战技巧,帮助开发者规避常见问题,提升系统稳定性与性能。 阅读详情

相关推荐

在win10系统上安装opnet14.5注意事项和步聚

opnet 14.5安装避坑!

miracle_eicont的专栏 1037

Callback Hell

Info: callback hell

Erice_s的博客 506

《缠中说禅108课》5:市场无须分析,只要看和干

喜欢吹牛皮的,在市场里最常见,例如一种以分析市场、吹牛皮为生的职业,叫什么股评、专家的。此类人不过是市场上的寄生虫,真正的猎手只会观察、操作,用嘴是打不了豺狼的。 市场就是一个狩猎场,首先你要成为一个好猎手,而一个猎手,首先要习惯于无言。如果真有什么真理,那真理也是无言的。可言说的,都不过是人类思想的分泌物,臭气熏天。真不可言说了,就无不可言,言而无言,是乃真言。 一个好的猎手,可以没有嘴巴,但一定会有一双不为外物所动的眼睛,在这眼睛下,一切如幻化般透明。要不被外物所动,则首先要不被自我所迷惑,其实..

BenRen1314的博客 800

muduo框架内核剖析

muduo 网络框架分析: 首先我们要分析的肯定是能撑起muduo框架的核心骨架,moduo reactor的核心骨架是三个类,channel、Eventpool和Poller 首先看Channel,channel是用来让事件可以在reactor之中自由穿梭的,由于多线程各个线程之间都能共享内存,所以线程之间的通讯一般采用内存复制作为主要的通讯手段,muduo多线程采用的是one thread per loop,意思就是每一个线程都有一个main loop。 muduo源码简单易懂,设计小巧,先从使用

qq_32783703的博客 542

【YOLO 系列】基于YOLO V8的智能车载交通标志识别系统【python源码+Pyqt5界面+数据集+训练代码】

本文详细介绍了基于YOLO V8构建智能车载交通标志识别系统的完整流程。从环境搭建、数据集准备、模型训练到PyQt5图形界面开发,提供了Python源码和实战代码,帮助开发者快速实现高精度、实时的交通标志检测应用,提升驾驶辅助系统的开发效率。

wdx012345的博客 966

LaTeX公式转Word竟这么简单?Python三行代码实现学术论文格式无忧

本文介绍如何利用Python的latex2word库,仅需三行代码即可将LaTeX数学公式精准转换为Word原生Office Math对象,解决学术写作中LaTeX与Word格式割裂的难题。该方法支持批量处理、格式保真,并能与Markdown、Jupyter Notebook等工具集成,构建自动化写作流程,实现学术论文格式无忧。

qsc90123456的博客 295

《muduo网络库》学习笔记——TcpClient剖析

muduo用TcpClient发起连接,TcpClient有一个Connector连接器,TcpClient使用Connector发起连接, 连接建立成功后, 用socket创建TcpConnection来管理连接, 每个TcpClient class只管理一个TcpConnecction,连接建立成功后设置相应的回调函数。很显然,TcpClient用来管理客户端连接,真正连接交给Connector。 调用过程如下:TcpClient::connect()——>Connector::start()—

baidu_15952103的博客 665

深度强化学习训练结果曲线绘制教程

使用python语言,只调用matplotlib库,绘制训练过程中保存的强化学习训练曲线。模仿经典论文中的训练曲线,多次训练取平均,并绘制出阴影区域。

加斯顿工程师的博客 910

TcpServer

服务端类,一个服务端只需要一个该实例。 TcpServer::TcpServer(EventLoop* loop, const InetAddress& listenAddr, const string& nameArg, Option option) : loop_(CHECK_NOTNULL(loop)), ipPort_(listenAddr.t

qu1993的博客 2404

基于遗传算法改进BP神经网络的电池容量SOC预测

,遗传算法BP神经网络能很好的实现对电池容量soc的训练和预测,BP神经网络是一种成熟的神经,相对于其他神经网络,拥有很多的训练函数,传递函数,可以调节的参数非常多,对各种问题都可以达到一个比较理想的效果,关键看如何调试参数,选择训练传递函数,遗传算法改进BP神经网络的初始权值阈值,达到改进BP神经网络的目的,从而更好的实现对电池容量SOC的预测

abc991835105的博客 764

基于YOLOv8的违规抽烟/打电话检测系统:从数据集构建到部署实战

模型优点缺点精度高速度慢(5 FPS)SSD速度快小目标检测差YOLOv5平衡性好官方支持停止YOLOv8最新、最快、最准需要PyTorch环境YOLOv8相比前代:骨干网络升级(C2f模块)无锚框检测(Anchor-Free)动态任务对齐分配(TaskAlignedAssigner)支持分类/检测/分割/姿态估计。

YOLO 97

Zeroc Ice TCP长连接 实现推送功能

业务场景 公司目前推送方案踩过很多坑,用过极光的(我们使用电信定向卡,遇到较多问题,定向ip等等,而且极光偶尔不太稳定推送无法到达,使用第三方避免不了这种问题)、用过自建的UDP推送(UDP会有丢包的情况)还稍微好一点,但是都会有问题,目前我们打算使用Ice的长连接,使设备和服务器保持一个tcp的长连接,实现实时推送的功能。解决的问题 1. 实时推送(双向)

jerome 7195

RK3588 hdmiout调试(一)

RK3588 hdmiout调试(一)

目前从事linux驱动开发,多交流多学习吧 5169

《Muduo网络库:好的服务器设计》

好的服务器设计原则

2202_75924820的博客 468

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

muduo-源码分析(前言0)

前言0 个人高性能、高并发linux服务器端编程(网络编程)比较感兴趣,自己写过一些简单的tcp通信程序,用进程池实现简单CGI服务器,用线程池实现简单web服务器。熟悉c++编程语言,但是没有用c++参与过一个项目,所以想寻找一个开源项目,用c++自己实现一个相对完整的网络库,所以选择了muduo开源网络库作为学习的第一个系统。因为他的代码量比较小,书中提到了如何借助现成库来发挥C++的

扎扎实实写代码的专栏 532

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

构建C++开源项目导航图:从筛选到实践的系统化指南

在软件工程领域,开源项目是学习和实践的重要资源。理解开源项目的评估标准、设计原理和集成方法,是提升工程能力的关键。开源项目的价值不仅在于其功能实现,更在于其代码设计、工程实践和社区生态所体现的技术思想。通过系统化的分类、深度评估和实操分析,开发者可以高效筛选出高质量项目,并将其应用于高性能服务器、嵌入式系统、游戏引擎等实际场景。本文以C++开源项目为例,详细阐述了如何构建一个结构化的项目收集库,并重点以Muduo网络库为案例,解析其Reactor模式、线程模型等核心设计,为开发者提供从学习到贡献的完整路径。

weixin_32075843的博客 215

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

最长递增子序列(LIS)动态规划详解:从O(n²)到O(n log n)的C++模板与工程实践

动态规划是解决最优化问题的核心算法范式,其核心思想是通过状态定义和状态转移,以空间换时间,避免子问题的重复计算。在序列处理领域,最长递增子序列(LIS)问题是理解动态规划状态设计的经典入门案例。通过定义`dp[i]`为以第i个元素结尾的LIS长度,并利用`dp[i] = max(dp[i], dp[j] + 1)`进行转移,可以构建出直观的O(n²)解法。为了应对更大规模的数据,可以引入贪心策略结合二分查找进行优化,将复杂度降至O(n log n),这体现了算法优化的重要技术价值。掌握LIS的模板与思想,不

weixin_33766805的博客 493

加班之余从零写了个 spdlog 风格的日志库

两周前开始动手,580 行代码,175 万 msg/s。这篇文章记录每一层的设计决策和踩过的坑。

Elizabeth_Booker的博客 197

chat集群聊天室项目 代码+讲解(一):网络模块

文章目录前言简单架构图代码讲解setConnectionCallbacksetMessageCallback 前言 准备翻新一下我那个C++集群聊天室项目的讲解博客,那个系列刚开始讲的还比较有点耐心,后面就直接堆代码了,大家互相理解理解,那确实有点触碰到我目前的极限了,能写下来就不错了。 勉强把项目整好之后我就去看muduo了(好像还有最后一篇《TCPServer》还没放出来哈,真的是因为VScode坏了,然后又有一件不得不做的事情拖住了几天时间。)目前已经粗略的捋了一遍muduo的源码,这周就把项目和..

看,未来的博客 1281

Muduo(C++11版本) 源码剖析(五)———TcpConnection设计

Rt

苏州-青蛙 688

《C++开源库介绍与使用》MongoDB 和 MQTT)的完整文章

MongoDB 和 MQTT)的完整文章,延续前文(jsoncpp、RapidJson、TinyXML、libcurl、zip.cpp/unzip.cpp、libqr、libpng、stb_image、libwebsockets、SQLite、FFmpeg、WebRTC、CEF、SDL、CrashRpt/CrashPad、ReactOS、boost、muduo、libevent、OpenCV、Yolo、RabbitMQ、Redis、ZooKeeper)的结构和深度。

专注于前沿技术的探索与实践,热衷于从代码逻辑、架构设计到行业应用等多维度深挖技术本质。期待在技术之路上与你共同成长~ 1231

10.继续完善Connection类,单Reactor模式成型

Reactor就是核心类EventLoop,就是一个循环。简单点说,其实就是一个epoll,通过epoll_wait()函数来进行dispatch。黄色的read(),send()这些就是可以看成是Connection类。这样,基础的单Reactor的模型就形成了。这是一个重要的版本,之后的版本都是在这个基础上面添加内容的,例如需要使用多线程。

m0_57408211的博客 606

C++实现集群聊天服务器

所有代码加起来两千行,里面用到了语言、数据结构、计网、操作系统、数据库、redis等知识,可谓是麻雀虽小五脏俱全。

美好的事情即将发生 1663

muduo源码剖析 - TcpConnection

muduo源码剖析

YanWenCheng_的博客 835

muduo::TcpConnection分析

muduo::TcpConnection分析

KangRoger的专栏 3914
上一篇: muduo网络库脉络分析(1)
下一篇: SCTP协议详解与实例
Shreck66
博客等级 码龄12年 119粉丝 91原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值