为赫兹量化开发MQTT客户端:TDD方法3

到目前为止,在第1部分和本系列的第2部分中,赫兹量化一直在处理MQTT协议的非操作部分的一小部分。我们在两个独立的头文件中组织了所有的协议定义、枚举和一些将在类之间共享的公共函数。此外,赫兹量化编写了一个接口作为对象层次结构的根,并在一个类中实现了它,其唯一目的是构建一个一致的MQTT CONNECT数据包。同时,我们一直在为构建数据包所涉及的每个函数编写单元测试。尽管我们将生成的数据包发送到本地MQTT代理,以检查它是否会被识别为格式良好的MQTT数据包,但从技术上讲,这一步骤是不需要的。由于我们使用固定数据来提供函数参数,所以我们知道我们是在孤立地测试它们,我们知道我们以独立于状态的方式测试它们。这很好,我们将努力继续以这种方式编写我们的测试,从而编写我们的函数。这将使我们的代码更加灵活,允许我们在不更改测试代码的情况下更改函数实现,只要我们有相同的函数签名。

从现在起,赫兹量化将处理MQTT协议的操作部分。毫不奇怪,它在OASIS标准中被命名为Operational Behavior(操作行为)。也就是说,从现在起,我们需要处理从服务器发送的数据包。我们的客户端必须能够识别服务器数据包类型及其语义,并且必须能够在给定的上下文中选择适当的行为,在每个可能的客户端状态中选择合适的行为。

为了能够处理此任务,我们必须在响应的第一个字节中识别服务器数据包类型。如果它是CONNACK数据包,我们必须读取其连接原因代码(Connect Reason Code),并做出相应的反应。

添加图片注释,不超过 140 字(可选)

(CONNECT)设置客户端连接标志

当我们的客户端请求与服务器连接时,它必须通知服务器

  • 代理的一些期望的能力,

  • 是否它将需要使用用户名和密码进行身份验证,

  • 以及该连接是否是新会话,还是它正在恢复先前打开的会话。

这是通过在“Protocol Name(协议名称)”和“Protocol Version(协议版本)”之后的 Variable Header (变量头)的开头设置一些位标志来实现的。CONNECT 数据包上的这些位标志被命名为 CONNECT Flags (连接标志)。

请记住,位标志是布尔值。它们可能被赋予不同的名称或表示,但布尔值只有两个可能的值,通常是true或false。

添加图片注释,不超过 140 字(可选)

图01-用于表示布尔值的常用术语

OASIS标准一致使用1(一)和0(零)。我们将在这里大部分时间使用true和false,最终,我们将使用 set 和 unset。这将使文本更具可读性。此外,我们的公共API始终使用true和false来设置这些值,因此使用这些术语应该会使关注库开发的读者更容易理解本文。

添加图片注释,不超过 140 字(可选)

图02 - OASIS连接标志位

正如您在上图中的OASIS表中所看到的,第一个位(bit_0)是保留的,我们必须将其单独保留:置零、未检查、布尔值为false、未设置。如果我们设置它,我们将有一个格式不正确的数据包(Malformed Packet)。

Clean Start (bit_1)

赫兹量化软件可以设置的第一个位是第二个位。它用于设置“Clean Start”标志——如果为true,服务器将执行“干净启动(Clean Start)”并丢弃与我们的客户端标识符相关联的任何现有会话。服务器将启动一个新会话。如果未设置,服务器将恢复我们以前的会话(如果有),或者如果没有与我们的客户端标识符关联的现有会话,则启动新会话。

这就是我们现在设置/取消设置此标志的函数。

 
 

void CPktConnect::SetCleanStart(const bool cleanStart) { cleanStart ? m_connect_flags |= CLEAN_START : m_connect_flags &= ~CLEAN_START; ArrayFill(ByteArray, ArraySize(ByteArray) - 1, 1, m_connect_flags); }

我们通过逐位运算来切换值。我们使用三元运算符来切换布尔赋值和复合赋值,以使代码更加紧凑。然后我们将结果存储在m_connect_flags私有类成员中。最后,我们通过调用内置函数ArrayFill,用新值更新表示CONNECT数据包的字节数组。(请注意,使用数组填充的最后一步是我们稍后可能会更改的实现细节。)

我们的一个测试中的这一行显示了它是如何被调用的。

 
 

CPktConnect *cut = new CPktConnect(buf); //--- Act cut.SetCleanStart(true);

Bit

7

6

5

4

3

2

1

0

User Name Flag

Password Flag

Will Retain

Will QoS 2

Will QoS 1

Will Flag

Clean Start

Reserved

X

X

X

X

X

X

1

0

表01-位标志Clean Start(bit_1)设置为true–MQTT v5.0

我们将广泛使用此模式来切换布尔标志:三元运算符和带复合赋值的逐位运算。

以下三个名为 Will ‘Something’ 的标志 旨在表达我们对服务器具有某些功能的愿望。他们通知服务器,我们“愿意”服务器能够

  1. 存储 Will 消息,并将其与我们的客户端会话相关联(稍后将对此进行详细介绍);

  2. 提供特定的QoS级别,通常高于QoS 0,如果没有设置,则为默认值;

  3. 保留 Will 信息,并在 Will 信息设置为true的情况下将其发布为“retained(保留)”(见下文)

Will Flag (bit_2)

第三位用于设置Will Flag –如果设置为true,我们的客户端必须提供“在网络连接未正常关闭的情况下”发布的Will 消息。人们可以将Will 消息视为一种客户在面对订阅者时死去后的“遗言”。

 
 

void CPktConnect::SetWillFlag(const bool willFlag) { willFlag ? m_connect_flags |= WILL_FLAG : m_connect_flags &= ~WILL_FLAG; ArrayFill(ByteArray, ArraySize(ByteArray) - 1, 1, m_connect_flags); }

它的调用方式与上一个函数相同。

 
 

//--- Act CPktConnect *cut = new CPktConnect(buf); cut.SetWillFlag(true);

Bit

7

6

5

4

3

2

1

0

User Name Flag

Password Flag

Will Retain

Will QoS 2

Will QoS 1

Will Flag

Clean Start

Reserved

X

X

X

X

X

1

X

0

表02-位标志 Will Flag(bit_2)设置为true–MQTT v5.0

Will QoS (bit_3, bit_4)

与前面的两个标志不同,如果客户端请求QoS级别2,则此功能需要设置两个位,即第四和第五位。QoS代表服务质量(Quality of Service),可以是三者之一。

添加图片注释,不超过 140 字(可选)

图 03 - OASIS QoS 定义

从最不可靠到最可靠的交付系统,它们是:

QoS 0

QoS 0最多设置一次交付。这是一种“发射就结束”,发送人将尝试一次,消息可能会丢失。没有来自服务器的确认。这是默认值,也就是说,如果在位3和4上没有设置任何内容,则客户端请求的QoS级别为QoS 0。

QoS 1

QoS 1 设置至少传递一次。它有一个确认收到的 PUBACK。

相同的函数定义模式。

 
 

void CPktConnect::SetWillQoS_1(const bool willQoS_1) { willQoS_1 ? m_connect_flags |= WILL_QOS_1 : m_connect_flags &= ~WILL_QOS_1; ArrayFill(ByteArray, ArraySize(ByteArray) - 1, 1, m_connect_flags); }

相同的函数调用模式。

  • 20
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值