重写muduo网络库之调用流程的梳理

目录

1、流程叙述

2、我们看看TcpServer的构造都做了什么?

3、start()

3.1 开启loop

3.2 连接的建立

3.3 数据的收发

4、连接的关闭


muduo网络库各组件梳理见此博客

重写muduo库之组件梳理

1、流程叙述

首先,我们是怎么使用的?

1.定义一个loop,就是baseloop
2.InetAddress打包了IP地址和端口号
3.创建server对象,给到EchoServer的构造函数,通过其参数进行初始化底层的TCPserver对象(相当于创建了TcpServer对象),保留了loop
4.设置了2个回调setConnectionCallback、setMessageCallback
5.设置了底层的loop线程的数量(这个数量不包括baseloop)

很好的把网络代码和业务代码分离了,我们只需要做开发者需要关注的:
6.我们用户作为开发者只需要关注下面的2个方法:

响应连接的建立和断开、响应读写事件

设置完之后
7.server.start();启动loop   loop.loop()

总结而来就是:首先构建tcpserver对象,设置回调方法,然后设置底层的loop线程的数量,然后调用start方法,最后开启主线程的loop

2、我们看看TcpServer的构造都做了什么?

创建了Acceptor,EventLoopThreadPool(还没有开启loop线程)

首先Acceptor创建了一个非阻塞的listenfd,然后把它打包成1个acceptchannel,准备往mainloop的poller上扔。

然后设置了一些tcp选项,创建socket,绑定bind,给channel设置回调,就是readcallback

也就是说:Acceptchannel只关心读事件。
只关心acceptchannel有新用户的连接的事件,底层的channel会去执行readcallback,对于Acceptor的readcallback执行的是handleRead

我们回过来继续看tcpserver的构造函数,接下来创建了EventLoopThreadPool(还没有开启loop线程),

然后执行了setNewConnectionCallback,我们刚才看到acceptor的构造函数

绑定了一个setReadCallback,也就是说,有新用户的连接,底层的channel就会去执行readcallback,因为有新用户的连接,响应了epollin事件,然后就执行readcallback

对于acceptor的setReadCallback执行的就算是Acceptor::handleRead。

我们进去看看handleread,会发现执行的是newConnectionCallback这个回调

这个里面的回调newConnectionCallback是谁设置的?通过setNewconnectionCallback设置的


这个setNewconnectionCallback是谁设置的?是最上层TcpServer设置的!

由上图,我们也就知道了,注册在mainloop上的acceptor,当有新用户连接,成功以后,经过上面一串,最终执行的是TcpServer的newConnection方法。

我们继续看TcpServer

3、start()

3.1 开启loop

通过atomic变量started控制一下,注意要将其初始化为0,只能取启动1次。

我们看第一句代码,threadpool启动底层线程池,创建loop子线程,并且开启loop的loop()
子线程创建执行的就是

我们设置的线程的回调方法就是

58行马上就启动loop()了
启动的时候,为了能把处于睡眠中的subloop唤醒,每个loop都有一个wakeupfd注册在相应loop的子线程的poller上。

接着我们看start的第二句

执行acceptor的listen方法,把acceptorchannel注册在baseloop上的poller上。

这一切就都准备好了
main函数最后一句开启baseloop的loop

我们在调用的三步骤:
1、构建TcpServer对象,同时包含了注册回调,设置底层线程的个数,和图中扩展的内容。
2、start开启loop子线程,注册wakeupfd,能够让主线程mainloop来唤醒子线程loop。然后acceptor listen,把listenfd打包成一个acceptorchannel注册到baseloop上。
3、最后启动loop();

我们看看acceptor的listen

muduo库:mainloop和subloop之间并没有同步队列,并没有使用生产者消费者模型:mainloop生成连接,放到同步队列里面,subloop从同步队列去自己取连接,做成异步的生产连接和消费连接。并没有。
而是用系统调用eventfd,创建wakeupfd,可以用它直接做线程间的notify,就是通知,唤醒,效率是非常非常高的。
在libevent上用的是socketpair这个系统调用,创建的是基于Unix本地通信的双向通信的套接字。

我们继续看,现在有一个新的连接了,mainloop就要返回了,执行acceptorchannel的readcallback,最终调用的是TCPserver的newconnection,就是有一条新的连接来了。

首先,通过轮询算法选择一个subloop,让这个ioloop指针指向它

接着创建1个tcpconnection对象

然后设置了一些回调,这些回调将来由TcpConnection设置到底层的channel里面。


主要的是设置了CloseCallback,当fd被关闭的时候,最终回调到TcpServer 的removeconnection,最终执行下面这个方法

这个ioLoop是肯定是在当前的主线程里去执行的,但是主线程访问ioLoop访问的肯定是一个子线程对应的loop,所以这里的ioLoop->runInLoop肯定不是在主线程里面执行的,除非是没有设置子线程(setthreadnum),ioLoop永远指向baseLoop。
我们看看runInLoop函数

如果执行的loop就在当前线程中(没有设置子线程数量),直接执行回调cb(),否则queueInloop。

queueInloop就是:每一个eventloop都有一个成员变量:wakeupfd,现在要在一个subloop里面执行下面这个方法:


通过这个指针找到subloop的wakeupfd,往wakeupfd上写数据,把相应的subloop唤醒,唤醒以后就去执行这个connectionEstablished,

3.2 连接的建立

我们进入connectEstablished


设置了状态,一个connection肯定是包含有一个channel,因为一个connection表示一个connectfd,只要有socketfd,就会打包成1个channel。
这里用channel绑定了当前 的TcpConnection,因为只有channel才能收到poller给它通知的事件回调,它执行的事件回调都是TcpConnection设置给它的,如果TcpConnection由于一些原因这个对象TcpConnection没有了,那channel到时候还执行不执行回调?
所以,channel在这里使用了 weakptr弱智能指针来记录了这个TcpConnection对象,到时候通过弱智能指针的提升来监测TcpConnection是否存活,存在就执行相应的回调,不存在就不执行了。避免了错误发生。
然后channel调用enableReading函数,向相应的poller注册channel,唤醒后把当前TcpConnectionchannel注册在它选择的某个subloop上了,然后再执行connectionCallback,对于测试代码来说,我们看到的就是下图代码中,日志的打印显示建立的成功。

在主函数调用中,新连接来了,就是上述的处理过程。

3.3 数据的收发

连接成功,有数据通信怎么办?
对于新连接来说,都是enabler eading注册了socketfd的epollIn事件,如果有相应的可读事件到来,那么相应的loop线程的poller就会返回,返回以后就执行相应的channel的readcallback事件


通过的是

执行的就是Tcpconnection的handleread

handleread开始读数据,数据读上来

调用messagecallback,相应的响应就是给上层应用报上来,onMessage这个函数被调用了,回调给用户。

通过buf->retrieveALLAsString拿到原始字符串,反序列化得到json或者pbbuff,然后业务处理,然后响应send。
所以说,相应的channel有可读事件发生,subloop就会回调channel的readcallback,tcpconnection给相应的channel的readcallback绑定的就是tcpconnection的handleread,handleread通过inputbuffer输入缓冲区读取相应的socketfd上的数据,读取完,回调用户设置的messagecallback,

然后用户这里就响应了

4、连接的关闭

如果有异常,对端关闭了或者是当前服务端在这里主动调用shutdown,底层的channel都会响应closecallback

这个closecallback,TCPconnection设置的是哪个回调?handleClose


handleclose执行disableAll把对应的channel和感兴趣的事件从poller上删除。

然后执行用户的回调。


对于使用者来说,onconnection又被回调了,这次是断开连接的回调。

执行tcpconnection的


执行TcpServer::newConnection的


就调用到removeConnection

执行removeConnectionInLoop


在TCPserver里,有一个connectionMap,把这个connection从connectionsmap删除掉,然后getloop,获取这条连接所在的子loop,执行connectDestroyed,

因为已经在handleclose中设置成kDisconnected了,所以此处进不去if语句,直接执行channel_->remove(),删掉channel,如果从其他地方进来,状态是已连接的,则执行if语句,断开连接

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/12413.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【iOS】工厂模式

文章目录 前言设计模式的三大原则简单工厂模式工厂方法模式抽象工厂模式关于三兄弟的升级与降级注意 前言 上文讲完了iOS的架构模式,接下来聊一聊设计模式,设计模式有许多,主要介绍一下工厂模式 设计模式的三大原则 S 单一职责原则 告诉我…

PBR系列-光之简史

作者:游梦 ​ 欢迎进入官网体验使用:Mapmost——让人与机器联合创作成为新常态 ​说到PBR理论分为三大理论:物理光源、物理材质与物理相机,三者都与光有着千丝万缕的关系,原打算这期讲解物理材质,在梳理知…

OpenHarmony 3.1 Release实战开发 + Linux 原厂内核Launcher起不来问题分析报告

1、关键字 Launcher 无法启动;原厂内核;Access Token ID; 2、问题描述 芯片:rk3566;rk3399 内核版本:Linux 4.19,是 RK 芯片原厂发布的 rk356x 4.19 稳定版内核 OH 版本:OpenHa…

elementui,iview等 表格单元格合并之固定列

要的效果如下 需要合并 show weak 及 Siginin这三列 上代码 <template><Table:columns"columns":span-method"handleSpan":data"data"bordersize"small"ref"table"></Table> </template> <sc…

R实验 基础(一)

实验目的&#xff1a; 了解实验报告书的书写要求&#xff1b;掌握R、RStudio的下载与安装&#xff1b;熟悉R的界面及基本操作&#xff1b;进一步熟悉R和RStudio的界面及基本操作&#xff1b;初步了解R的绘图和程序包的下载、安装和加载使用。 实验内容&#xff1a; 了解实验报…

Python sort() 和 sorted() 的区别应用实例详解

大家好&#xff0c;今天针对 Python 中 sort() 和 sorted() 之间的区别&#xff0c;来一个实例详细解读。sort — 顾名思义就是排序的意思&#xff0c;它可以接收的对象为可迭代的数据类型。今天以列表为例子演示两者的不同点、相同点&#xff0c;以及其中一些常用的高级参数使…

【知识碎片】2024_05_14

本篇记录了两道关于位运算的选择题&#xff0c;和一道有点思维的代码题。 C语言碎片知识 求函数返回值&#xff0c;传入 -1 &#xff0c;则在64位机器上函数返回&#xff08; &#xff09; int func(int x) {int count 0;while (x){count;x x&(x - 1);//与运算} return c…

24/05/14总结

签到2&#xff1a; 签到界面上有时间显示&#xff0c;签到码输入框&#xff0c;开始签到&#xff0c;当倒计时结束&#xff0c;老师端和学生端都会显示签到结果&#xff0c;所以签到结果需要建表&#xff1a;&#xff08;签到了的学生和未签到的学生&#xff0c; 这次签到的时间…

详述进程的地址空间

进程的地址空间 合法的地址 (可读或可写) 代码 (main, %rip 会从此处取出待执行的指令)&#xff0c;只读数据 (static int x)&#xff0c;读写堆栈 (int y)&#xff0c;读写运行时分配的内存 (???)&#xff0c;读写动态链接库 (???) 非法的地址 NULL&#xff0c;导致 se…

【微命令】git config如何配置全局的用户和邮箱?(--global user.name、user.email;git config --help)

虽然经常用&#xff0c;也经常忘记&#xff0c;特此记录。 命令 git config --global user.name "myname" git config --global user.email test163.com另外一种方式 help git config --help |grep email | grep name直接help查看

Git系列:git log 掌握版本控制的精髓

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

【leetcode面试经典150题】-27. 移除元素

88.合并两个有序数组 1 题目介绍1 个人解题思路1.1 解题代码1.2 思路解析 2、分析官方题解2.1 单侧双指针2.2 双侧双指针 1 题目介绍 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外…

Echarts结课之小杨总结版

Echarts结课之小杨总结版 前言基础回顾框架sale框架代码&#xff1a; user框架基础代码&#xff1a; inventory框架基础代码&#xff1a; total框架基础代码&#xff1a; 基础设置1.标题(Title)2.图例(Legend)实现 3.工具提示(Tooltip)实现 4.X轴(X Axis) 和 Y轴(Y Axis)5.数据…

「Qt Widget中文示例指南」如何实现一个快捷编辑器(二)

Qt 是目前最先进、最完整的跨平台C开发工具。它不仅完全实现了一次编写&#xff0c;所有平台无差别运行&#xff0c;更提供了几乎所有开发过程中需要用到的工具。如今&#xff0c;Qt已被运用于超过70个行业、数千家企业&#xff0c;支持数百万设备及应用。 快捷编辑器示例展示…

Leetcode 第 129 场双周赛题解

Leetcode 第 129 场双周赛题解 Leetcode 第 129 场双周赛题解题目1&#xff1a;3127. 构造相同颜色的正方形思路代码复杂度分析 题目2&#xff1a;3128. 直角三角形思路代码复杂度分析 题目3&#xff1a;3129. 找出所有稳定的二进制数组 I思路代码复杂度分析 题目4&#xff1a;…

电子邮箱是什么?怎么申请一个电子邮箱?

电子邮箱是我们沟通的工具&#xff0c;细分为免费版电子邮箱和付费版电子邮箱。怎么申请一个属于自己的电子邮箱&#xff1f;今天小编就分享一下电子邮箱注册教程&#xff0c;手把手教您注册一个电子邮箱。 一、电子邮箱的定义 电子邮箱&#xff0c;简称邮箱&#xff0c;是一…

BGP路由优选

1.BGP路由优选规则 上述规则依序排列&#xff0c;BGP进行路由优选时&#xff0c;从第一条规则开始执行&#xff0c;如果根据第一条规则无法作出判断&#xff0c;例如路由的Preferred-Value属性值相同&#xff0c;则继续执行下一条规则&#xff0c;如果根据当前的规则&#xff0…

如何快速打开多个网页?

在平常的工作当中&#xff0c; 如果每天都需固定打开几个网站&#xff0c;可以通过创建一个批处理&#xff0c;一键打开需要的所有网站。 使用方法&#xff1a; 在桌面新建一个txt文本&#xff0c;按照以下格式输入代码&#xff0c;并将需要打开网站的地址输入进去。 ​ ec…

JavaScript异步编程——11-异常处理方案【万字长文,感谢支持】

异常处理方案 在JS开发中&#xff0c;处理异常包括两步&#xff1a;先抛出异常&#xff0c;然后捕获异常。 为什么要做异常处理 异常处理非常重要&#xff0c;至少有以下几个原因&#xff1a; 防止程序报错甚至停止运行&#xff1a;当代码执行过程中发生错误或异常时&#x…

虚拟化技术 在vCenter Server创建数中心、添加主机

一、实验内容 1.安装Flash 2.在vCenter Server创建数中心、添加主机 二、实验主要仪器设备及器材 1.安装有64位Windows操作系统的台式电脑或笔记本电脑&#xff0c;建议4C8G或以上配置 2.在Windows Server 2008 R2已安装vCenter Server 3.Adobe Flash Player 12.0.0.70.e…