RabbitMQ-客户端源码之AMQCommand
AMQCommand不是直接包含Method等成员变量的,而是通过CommandAssembler又做了一次封装。
接下来先看下CommandAssembler类。此类中有这些成员变量:
/** Current state, used to decide how to handle each incoming frame. */
private enum CAState {EXPECTING_METHOD, EXPECTING_CONTENT_HEADER, EXPECTING_CONTENT_BODY, COMPLETE
}
private CAState state;/** The method for this command */
private Method method;/** The content header for this command */
private AMQContentHeader contentHeader;/** The fragments of this command's content body - a list of byte[] */
private final List bodyN;
/** sum of the lengths of all fragments */
private int bodyLength;/** No bytes of content body not yet accumulated */
private long remainingBodyBytes;
- CAState state标识这此Command目前的状态,是准备处理Method(EXPECTING_METHOD),还是处理Content header(EXPECTING_CONTENT_HEADER),还是准备处理Content body(EXPECTING_CONTENT_BODY),还是以及完成了(COMPLETE)。
- Method method代表type=Method的AMQP帧
- AMQContentHeader contentHeader代表type=Content header的AMQP帧
- final List bodyN代表type=Content body的AMQP帧,就是真正的消息体(Message body)。
- bodyLength就是消息体大小
这个类中除了构造函数,getMethod, getContentHeader, getContentBody,isComplete这个几个方法,最关键的方法就是:
public synchronized boolean handleFrame(Frame f) throws IOException
{switch (this.state) {case EXPECTING_METHOD: consumeMethodFrame(f); break;case EXPECTING_CONTENT_HEADER: consumeHeaderFrame(f); break;case EXPECTING_CONTENT_BODY: consumeBodyFrame(f); break;default:throw new AssertionError("Bad Command State " + this.state);}return isComplete();
}
这个方法主要是处理AQMP帧的,根据CAState state来处理相应状态类型的帧,然后赋值给相应的成员变量。
采用consumeMethodFrame(Frame f)方法举个例子:
private void consumeMethodFrame(Frame f) throws IOException {if (f.type == AMQP.FRAME_METHOD) {this.method = AMQImpl.readMethodFrom(f.getInputStream());this.state = this.method.hasContent() ? CAState.EXPECTING_CONTENT_HEADER : CAState.COMPLETE;} else {throw new UnexpectedFrameError(f, AMQP.FRAME_METHOD);}
}
这个方法首先判断当前帧是否是Method帧(AMQP.FRAME_METHOD),然后调用AMQPImp.readMethodFrom的方法。就那Connection.Start这个真来将,它会从socket的输入流中读取:
public Start(MethodArgumentReader rdr) throws IOException {this(rdr.readOctet(), rdr.readOctet(), rdr.readTable(), rdr.readLongstr(), rdr.readLongstr());
}
对应于下图:
- 第一个rdr.readOctet()是指Version-Magor:0
- 第二个rdr.readOctet()是指Version-Minor:9
- 第三个rdr.readTable()是指Server-Properties
- 第四个rdr.readLongstr()是指Mechanisms
- 第五个rdr.readLongstr()是指Locales
而MethodArgumentReader.readOctet()就是:
public final int readOctet()throws IOException
{clearBits();return in.readOctet();//in对象是DataInputStream对象
}
写到这里,思路再跳回来,知道了底层其实是Socket的DataInputStream,其上只是做了封装再封装
CommandAssembler 中的handleFrame这个方法只在AMQCommand中的:
private final CommandAssembler assembler;
public boolean handleFrame(Frame f) throws IOException {return this.assembler.handleFrame(f);
}
只在这个方法中调用。CommandAssembler只是对Method,Content-Header,Content-Body做了一下封装。下面继续回到AMQCommand这个类中来。
仔细阅读源码的同学会发现在handleFrame方法当遇到类似Basic.Publish时会有Method,Content-Header,Content-Body一起的报文,那么handleFrame处理完Method之后就直接返回了,没有完全处理完,这该如何是好?
这个就又要联系到AMQConnection中的MainLoop的内部类了。此类中的关键代码如下:
while (_running) {Frame frame = _frameHandler.readFrame();if (frame != null) {_missedHeartbeats = 0;if (frame.type == AMQP.FRAME_HEARTBEAT) {// Ignore it: we've already just reset the heartbeat counter.} else {if (frame.channel == 0) { // the special channel_channel0.handleFrame(frame);} else {if (isOpen()) {// If we're still _running, but not isOpen(), then we// must be quiescing, which means any inbound frames// for non-zero channels (and any inbound commands on// channel zero that aren't Connection.CloseOk) must// be discarded.ChannelManager cm = _channelManager;if (cm != null) {cm.getChannel(frame.channel).handleFrame(frame);}}}}} else {// Socket timeout waiting for a frame.// Maybe missed heartbeat.handleSocketTimeout();}
}
可以看到这是一个一直轮询读取Frame并处理Frame的过程。在遇到类似Basic.Publish这种带Method, Content-Header, Content-Body的类型的报文时,会循环处理,直到处理完成。注意这里的Method, Content-Header以及Content-Body都是看成单个Frame的,也就是这个while循环要三次,而不是将Basic.Publish看成一个帧。
上面调用的handleFrame方法是AMQChannel类中的(详细可以参考([[五]RabbitMQ-客户端源码之AMQChannel][RabbitMQ-_AMQChannel])):
public void handleFrame(Frame frame) throws IOException {AMQCommand command = _command;if (command.handleFrame(frame)) { // a complete command has rolled off the assembly line_command = new AMQCommand(); // prepare for the next onehandleCompleteInboundCommand(command);}
}
可以看到只有当AMQCommand的handleFrame方法返回true时,即执行完成之后才会继续处理。
AMQCommand也有getMethod, getContentHeader, getContentBody等方法,这些都是间接调用CommandAssembler类中相应的方法的。
AMQCommand中也有个特别重要的方法:
/*** Sends this command down the named channel on the channel's* connection, possibly in multiple frames.* @param channel the channel on which to transmit the command* @throws IOException if an error is encountered*/
public void transmit(AMQChannel channel) throws IOException {int channelNumber = channel.getChannelNumber();AMQConnection connection = channel.getConnection();synchronized (assembler) {Method m = this.assembler.getMethod();connection.writeFrame(m.toFrame(channelNumber));if (m.hasContent()) {byte[] body = this.assembler.getContentBody();connection.writeFrame(this.assembler.getContentHeader().toFrame(channelNumber, body.length));int frameMax = connection.getFrameMax();int bodyPayloadMax = (frameMax == 0) ? body.length : frameMax- EMPTY_FRAME_SIZE;for (int offset = 0; offset < body.length; offset += bodyPayloadMax) {int remaining = body.length - offset;int fragmentLength = (remaining < bodyPayloadMax) ? remaining: bodyPayloadMax;Frame frame = Frame.fromBodyFragment(channelNumber, body,offset, fragmentLength);connection.writeFrame(frame);}}}connection.flush();
}
这段主要通过传输AMQP帧的,通过AMQChannel获取到通信链路connection,然后将AMQCommand对象自身的method成员变量(或者包括content-header以及content-body)传送给broker。这段方法里还有判断payload大小是否超过broker端所设置的最大帧大小frameMax,即(frameMax == 0) ? body.length : frameMax - EMPTY_FRAME_SIZE这段代码。当frameMax=0时则没有大小限制,当frameMax不为0时则按照payload拆分成若干的payload然后发送多个FRAME_BODY帧。
相关文章:
RabbitMQ-客户端源码之AMQCommand
AMQCommand不是直接包含Method等成员变量的,而是通过CommandAssembler又做了一次封装。 接下来先看下CommandAssembler类。此类中有这些成员变量: /** Current state, used to decide how to handle each incoming frame. */ private enum CAState {EXP…...
linux设置登录失败处理功能(密码错误次数限制、pam_tally2.so模块)和操作超时退出功能(/etc/profile)
一、登录失败处理功能策略 1、登录失败处理功能策略(服务器终端) (1)编辑系统/etc/pam.d/system-auth 文件,在 auth 字段所在的那一部分添加如下pam_tally2.so模块的策略参数: auth required pam_tally2…...
Centos7上Docker安装
文章目录1.Docker常识2.安装Docker1.卸载旧版本Docker2.安装Docker3.启动Docker4.配置镜像加速前天开学啦~所以可以回来继续卷了哈哈哈,放假在家效率不高,在学校事情也少点(^_−)☆昨天和今天学了学Docker相关的知识,也算是简单了解了下&…...
新瑞鹏“狂飙”,宠物医疗是门好生意吗?
宠物看病比人还贵,正在让不少年轻一族陷入尴尬境地。在知乎上,有个高赞提问叫“你愿意花光积蓄,给宠物治病吗”,这个在老一辈人看来不可思议的魔幻选择,真实地发生在当下的年轻人身上。提问底下,有人表示自…...
Spring循环依赖问题,Spring是如何解决循环依赖的?
文章目录一、什么是循环依赖1、代码实例2、重要信息二、源码分析1、初始化Student对Student中的ClassRoom进行Autowire操作2、Student的自动注入ClassRoom时,又对ClassRoom的初始化3、ClassRoom的初始化,又执行自动注入Student的逻辑4、Student注入Class…...
更改SAP GUI登录界面信息
在SAP GUI的登录界面,左部输入登录信息如客户端、用户名、密码等,右部空余部分可维护一些登录信息文本,如登录的产品、客户端说明及注意事项等,此项操作详见SAP Notes 205487 – Own text on SAPGui logon screen 维护文档使用的…...
分布式微服务架构下网络通信的底层实现原理
在分布式架构中,网络通信是底层基础,没有网络,也就没有所谓的分布式架构。只有通过网络才能使得一大片机器互相协作,共同完成一件事情。 同样,在大规模的系统架构中,应用吞吐量上不去、网络存在通信延迟、我…...
进大厂必备的Java面试八股文大全(2023最新精简易懂版,八股文中的八股文)
为什么同样是跳槽,有些人薪资能翻三倍?” 最近一个粉丝发出了灵魂拷问,类似的问题我收到过很多次,身边也确实有认识的同事、朋友们有非常成功的跳槽经历和收益,先说一个典型例子: 学弟小 A 工作一年半&am…...
都说测试行业饱和了,为什么我们公司给初级测试开到了12K?
故事起因: 最近我有个刚毕业的学生问我说:我感觉现在测试行业已经饱和了,也不是说饱和了,是初级的测试根本就没有公司要,哪怕你不要工资也没公司要你,测试刚学出来,没有任何的项目经验和工作经验…...
解决Idea启动项目失败,提示Error running ‘XXXApplication‘: Command line is too long
IDEA版本为:IntelliJ IDEA 2018.2 (Ultimate Edition)一、问题描述有时当我们使用IDEA,Run/Debug一个SpringBoot项目时,可能会启动失败,并提示以下错误。Error running XXXApplication: Command line is too long. Shorten comman…...
GB/T28181-2022针对H.265、AAC的说明和技术实现
GB/T28181-2022规范说明GB/T28181-2022相对来GB/T28181-2016针对H.265、AAC的更新如下:——更改了“联网系统通信协议结构图”,媒体流通道增加了 H.265、G.722.1、AAC(见 4.3.1,2016 年版的 4.3.1)。——增加了对 H.26…...
开关电源环路稳定性分析(11)——观察法找零极点
大家好,这里是大话硬件。 这篇文章主要是分享如何用观察法直接写出补偿网络中的零极点的表达式。 在前面的文章中,我们分别整理了OTA和OPA型的补偿网络,当时有下面的结论。 针对某个固定的补偿网络,我们可以用数学的方法推导补偿…...
焕新启航,「龙蜥大讲堂」2023 年度招募来了!13 场技术分享先睹为快
龙蜥大讲堂是龙蜥推出的系列技术直播活动,邀请龙蜥社区的开发者们分享围绕龙蜥技术展开,包括但不限于内核、编译器、机密计算、容器、储存等相关技术领域。欢迎社区开发者们积极参与,共享技术盛宴。往期回顾龙蜥社区技术系列直播截至目前已举…...
推广传单制作工具
临近节日如何制作推广活动呢?没有素材制作满减活动宣传单怎么办?小编教你如何使用在线设计工具乔拓云,轻松设计商品的专属满减活动宣传单,不仅设计简单,还能自动生成活动分享链接,只需跟着小编下面的设计步…...
软件设计(十一)数据结构(上)
线性结构 线性表 线性表是n个元素的有限序列,通常记为(a1,a2....an),特点如下。 存在唯一的一个称作“第一个”的元素。存在位移的一个称作“最后一个”的元素。除了表头外,表中的每一个元素均只有唯一的直接前趋除了表尾外&…...
https协议
文章目录对称加密方案非对称加密方案对称加密方案非对称加密方案对称加密方案非对称加密方案数字证书因为HTTP是明文传输,所以会很有可能产生中间人攻击(获取并篡改传输在客户端及服务端的信息并不被人发觉),HTTPS加密应运而生。 …...
深入浅出C语言——数据在内存中的存储
文章目录一、数据类型详细介绍1. C语言中的内置类型2. 类型的基本归类:二. 整形在内存中的存储1. 原码、反码、补码2. 大小端三.浮点数存储规则一、数据类型详细介绍 1. C语言中的内置类型 C语言的内置类型有char、short、int、long、long long、float、double&…...
在 Centos 上在线安装 GitLab
作为程序员,其中一个愿望是拥有一个自己的代码存储库。在支持私有部署的代码存储库产品中,GitLab 是比较著名的了,所以今天我总结了一下在 Centos 上安装 GitLab 的过程。 依赖 基础依赖 首先,需要安装部分基础的依赖ÿ…...
模型解释性:SHAP包的使用
本篇博客介绍另一种事后可解释性方法:SHAP(SHapley Additive exPlanation)方法。 1. Shapley值理论 Shapley值是博弈论中的一个概念,通过衡量联盟中各成员对联盟总目标的贡献程度,从而根据贡献程度来进行联盟成员的利益分配,避免…...
算法训练营 day45 动态规划 0-1背包理论 分割等和子集
算法训练营 day45 动态规划 0-1背包理论 分割等和子集 0-1背包理论 有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。 在下面的讲解中&…...
SSM框架
1.mybatis的底层原理 本质上就是使用反射和动态代理来实现对应的映射关系 2.日志级别 3.传递参数 单个参数的传递和多个参数的传递 Emp selectOne(Param(“xingming”) String name); List selectByCondition(Param(“name”) String name,Param(“sal”) double sal); 4.#和…...
教育行业需要什么样的客服系统?
某教育公司拥有素质教育、成人教育、智慧教育等多个业务板块,日常通过电商、线上媒体、线上线下授课等方式进行业务开展和品牌宣传,取得了非常不错的成绩,受到了很多人的好评反馈。 对于这样一个教育公司,客户来源广泛࿰…...
花房集团任命新首席财务官:已跌破IPO发行价,活跃用户下滑
上市刚满2个月,花椒母公司花房集团(HK:03611)的高管就发生了变更。2023年2月12日,花房集团披露的公告显示,董事会宣布赵磊为该公司首席财务官(CFO),自2023年2月10日起生效。 据贝多…...
儿童绘本馆图书借阅租赁知识付费小程序源码交流
1.分类图书 2.书单推荐 4.会员卡次、期限购买 5.借阅时间选择 6.积分签到 7.优惠Q领取 前端uniapp开发 后端thinkphp开发 完全开源 <template> <view class"sp-section sp-index"> <!-- search --> <view class&qu…...
Vue3 中 axios 的安装及使用
目录前言:一、什么是 axios ?二、Axios 的配置项三、Axios 的请求方式四、自定义创建实例五、Axios 请求错误处理六、Axios 解决跨域问题七、Axios 请求案例随机笑话大全总结:前言: 在编写vue里的项目时,必须要用和后台…...
Django设计模式以及模板层介绍
MVC和MTV 传统的MVC作用:降低模块间的耦合度(解耦)Django的MTV模式 作用:降低模块间的耦合度(解耦)什么是模板 1、模板是可以根据字典数据动态变化的html网页2、模板可以根据视图中传递的字典数据动态生成相…...
Linux信号一门搞定
1.信号是什么? 信号其实就是一个软件中断。 例: 输入命令,在Shell下启动一个前台进程。用户按下Ctrl-C,键盘输入产生一个硬件中断。如果CPU当前正在执行这个进程的代码,则该进程的用户空间代码暂停执行,…...
手撸一个动态Feign,实现一个“万能”接口调用
Feign,在微服务框架中,是的服务直接的调用变得很简洁、简单,而不需要再编写Java Http调用其他微服务的接口。 动态feign 对于fegin调用,我们一般的用法:为每个微服务都创建对应的feignclient接口,然后为每…...
Linux Capabilities 入门
目录 Linux capabilities 是什么? capabilities 的赋予和继承 线程的 capabilities Permitted Effective Inheritable Bounding Ambient 文件的 capabilities Permitted Inheritable Effective 运行 execve() 后 capabilities 的变化 案例 Linux capab…...
驱动 day6
关于设备树的理解: 设备树(Device Tree)是一种用于特定硬件设备的解释语法树。它用来表示存储有关主板硬件和CPU架构信息的数据在内核中的传递格式,使内核可以更好地了解硬件并支持它们,而不必编写固定的代码。设备节点…...
java做网站教程/怎么做百度搜索排名
在ArcGIS中使用镶嵌数据集,你为它构建过“概视图”,也就是overview吗?你有过疑问,这个概视图和影像金字塔是什么关系?对于单景影像(栅格数据集),为了加快影像显示速度,我…...
自做网站告白如何弄/网络广告营销的概念
一、thrift返回结果封装 Thrift文件添加版本号,方便对thrift的版本进行控制 服务与返回的数据类型分开定义 在项目中使用Thrift提供RPC服务时,很多情况下我们都会将返…...
asp做网站的缺点/百度搜索引擎优化相关性评价
源代码: Lib/filecmp.py filecmp 模块定义了用于比较文件及目录的函数,并且可以选取多种关于时间和准确性的折衷方案。对于文件的比较,另见 difflib 模块。 filecmp 模块定义了如下函数:filecmp.cmp(f1, f2, shallowTrue) 比较名为 f1 和 f2 …...
中山做app网站公司哪家好/爱站网的关键词是怎么来的
2019独角兽企业重金招聘Python工程师标准>>> 自己自学python,偶然间看到笨方法学python(作者是Zed Shaw)这一本书,在接下来的一段时间内,会完成书中所有的练习,希望自己能坚持下去,能够养成好习惯:读和写、注重细节、发现不同。 祝自己好运! 相应的环境: ubuntu 12.…...
担路网口碑做网站好吗/如何引流被动加好友微信
9991阴魂不散!多多QQ表情病毒奥秘(转)QQ表情本来是广受用户欢迎的一个实用工具,然而,最近有人却利用人们对QQ表情的喜爱,将其变成了一种恶性病毒。最近,笔者不断接到求助电话,受到一款名叫多多QQ表情病毒的骚扰。笔者随…...
高端网站建设批发/app推广渠道
在MainServlet中,当初始化resource actions之后,就开始初始化resource code ,这是由以下代码来完成的: if (_log.isDebugEnabled()) { _log.debug("Initialize resource codes"); } try { …...