<audio id="audio" title="03 | 网络协议：设备使用什么语言与互联网对话？" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/fb/de/fb9a147b654710c5b47d32fa93e01fde.mp3"></audio>

你好，我是郭朝斌。

在上一讲中，我为你介绍了物联网设备常用的几种无线通信技术。通过这些技术联网之后，物联网设备就可以向云平台上报数据了吗？还不可以。

成功传输数据的前提是，通信双方必须使用**同一种“语言”**。这就像，你拨通了比尔·盖茨的电话，如果说“喂，你好”，他大概会一头雾水；但如果说“Hello!”，他一下就能听懂了。

而物联网设备间沟通的语言，就是**网络协议**。说起网络协议，你可能马上就想到了 HTTP 协议。是的，在日常的Web开发中，我们总是需要跟它打交道，因为 HTTP  协议是互联网的主流网络协议。

类似地，应用在互联网中的网络协议，还有收发电子邮件的POP3 、SMTP 和 IMAP 协议，以及用于区块链中的 P2P 协议。

那你马上会问了，物联网设备之间的通信，可以直接使用这些协议吗？

## 物联网通信的特点

想要回答这个问题，我们得先来分析一下物联网的网络通信特点。

1. 物联网设备很大可能工作在**不可靠、高延迟的网络环境**中。

比如共享单车，使用 NB-IoT 这样的通信技术，本身的通信速率就只有不到几十Kbps；要是被人停在城市的角落里，信号可能很不稳定。

假设你使用 HTTP  协议，就需要单车先发出连接请求，然后等待服务器的响应（下发开锁指令）。这样一来，受网络通信质量的影响，很可能连接经常中断，而需要单车与服务器交互多次，那用户可能就要等很长时间。

对于这种场景来说，不只是HTTP，其他跟HTTP一样单向的、同步的网络协议，都不是理想的技术方案。

1. 物联网系统中，**设备数量多，<strong><strong>而且**</strong>交互非常复杂</strong>。

比如你家里的环境监测，温度、湿度、光照、二氧化碳、甲醛含量……这些都需要不同的设备测量，而且每个房间用到的设备也不同。

如果你让云平台的服务对每个设备分别做权限控制和数据阈值设置，这会非常麻烦。因为当数据的“生产者”和“消费者”直接交互时，要是没有中间角色基于共同的目标协调，双方的耦合度会很大，导致系统很难实现。

这时候，你需要把你家作为一个整体来处理，交互逻辑就会变得简单多了。

1. 设备经常需要**根据实际使用环境做增加、减少等调整**。

比如你用一个设备测量房间的温度，现在这个设备损坏了，你要换一个。你肯定不希望因为设备 ID 这么一个小小的变化，就要去修改判断房屋温度的逻辑代码，这太麻烦了，也不符合软件开发的开闭原则。

这要求系统必须具备可伸缩性（或者说可扩展性），设备的增减不会导致系统逻辑的调整。

正是因为这些特点，物联网系统在选择网络通信的协议时，一般采用**发布-订阅**的通信模式。为什么说发布-订阅模式适合呢？我来解释一下它的设计，你就明白了。

## 发布-订阅模式

发布-订阅模式包含三个角色，分别是发布者（Publisher）、经纪人（Broker）和订阅者（Subscriber），它们的关系如下图所示。

<img src="https://static001.geekbang.org/resource/image/b5/22/b597dfbda6f748c9858d021770be7a22.jpg" alt="">

三个角色之间的消息传递，基于一个重要的概念——主题。主题用于消息的过滤（或者说路由），它确定了消息的不同类别。消息传递的过程可以分为三步：

1. **发布者**负责生产数据。发布者发送某个主题的数据给经纪人，发布者不知道订阅者。
1. **订阅者**订阅经纪人管理的某个或者某几个主题。
1. 当**经纪人**接收到某个主题的数据时，将数据发送给这个主题的所有订阅者。

我们举个例子你就理解了。到中午了，你有点饿。今天吃什么呢？你想了想，拿出手机打开外卖App，选择了牛二楠家的咖喱牛肉盖饭，外加双份肥宅快乐水加冰。

当你发布牛二楠家的订单给外卖订单中心服务器时，隔壁的产品经理小王也在点外卖，他点了猪三排家的红烧排骨盖饭。

外卖订单中心收到这两个订单之后，会把你的订单发送给牛二楠家，把小王的订单发送给猪三排家。

<img src="https://static001.geekbang.org/resource/image/91/b7/91aff5a163b4944bf3481f30102e40b7.jpg" alt="">

相信你也看出来了，你和小王都是“发布者”，牛二楠家和猪三排家就是“订阅者”，而外卖订单中心就是“经纪人”。

当然，你内心可能在祈祷外卖订单中心出个错，把小王那个订单（猪三排家的红烧排骨盖饭）发送到做卤煮的猪三下水家那里，给他的午饭增加一点难忘的体验。

为什么我说发布-订阅模式适合物联网系统呢？因为在物联网场景中，一个传感器数据需要**触发多个服务或者终端执行动作**。

比如红外传感器，当它检测到有人体靠近时，就需要触发一系列动作：通知摄像头拍照，声光报警器执行报警，推送消息给主人的手机等。

怎么满足这种需求呢？我们最好让摄像头、声光报警器和手机都订阅“人体靠近”这个主题消息。当红外传感器被触发时，它发送人体靠近的消息，然后这些设备就能同时收到这个消息，接着完成系统定义的那些动作。这就是发布-订阅模式的工作方式。

另外，发布-订阅模式减少了发布者与订阅者之间的耦合度，所以网络不稳定导致的临时离线就不会影响彼此的工作。它的拓扑结构也使系统更容易扩展，更容易满足动态变化的需求。这些优点都使得发布-订阅模式在物联网应用协议中非常流行。

那么，具体有什么网络协议采用的是发布-订阅通信模式呢？MQTT 协议就是其中的佼佼者。

### MQTT

[MQTT](https://mcxiaoke.gitbooks.io/mqtt-cn/content/)（MQ Telemetry Transport）协议，是 IBM 公司在 1999 年开发的轻量级网络协议，它有三个主要特点：

1. **采用二进制的消息内容编码格式**，所以二进制数据、JSON和图片等负载内容都可以方便传输。
1. **协议头很紧凑，协议交互也简单**，保证了网络传输流量很小。
1. **支持3种 QoS****（Quality of Service，服务质量）****级别**，便于应用根据不同的场景需求灵活选择。

这里我解释一下什么是QoS。它是指通信双方关于消息传送可靠程度的协商。QoS 0，消息只发送一次，消息可能丢失；QoS 1呢，发送方会接收反馈，保证消息的送达，但是可能消息会重复。QoS 2级别，通过发送方和接收方的多次交互，保证消息有且只有一次。

现在我们说回MQTT。刚才提到的这三个特点，让 MQTT 协议非常适合计算能力有限、网络带宽低、信号不稳定的远程设备，所以它成为了物联网系统事实上的网络协议标准。关于 MQTT 协议的详细内容，我还会在进阶篇第8讲为你进一步剖析。

### AMQP

除了 MQTT 协议以外，也有其他采用发布-订阅模式的网络协议，比如 AMQP 协议。

虽然 AMQP 协议拥有庞大的特性集，比较重，不适合计算资源有限、对功耗要求严苛的物联网设备，但是它可以满足后台系统对于**可靠性**和**可扩展性**的要求。因此，它在物联网的平台系统中应用广泛。比如，在分布式系统中应用广泛的 RabbitMQ 消息中间件软件，就是基于 AMQP 实现的。

AMQP 和 MQTT 一样，也是基于 TCP 协议，采用二进制消息格式，也支持3个 QoS 级别。

顺带说一句，现在被广泛使用AMQP 1.0 和 AMQP 0.9.1 这两个版本，在设计上有很大的差异。你在查询资料或者应用这两个版本的AMQP协议时，一定要注意看版本，避免用错。

## 请求-响应模式

刚才我介绍了发布-订阅模式的很多好处，但是凡事都有例外，也有一些物联网应用场景，并不适合使用这种模式。

比如，现在小区里面都有智能快递柜，当你输入取件码后，服务器会向对应的柜门发送开门指令。

在发布-订阅模式下，服务器知道指令发送成功了，但是它无法知道柜门是否真的打开了。这时，你就需要让柜门能够向服务器反馈一下命令的执行结果。

当然，你也可以让服务器订阅一个“柜门关闭”的主题消息，然后等待柜门发布这个消息。但是这样的话就非常繁琐、不够直接。

在这种场景下，另一种通信模式就能派上用场了，那就是**请求-响应**模式。

请求-响应模式有两个角色，一个是客户端（Client），另一个是服务器（Server）。

**客户端**是请求数据或者服务的一方。**服务器**则用来接收客户端的请求，并提供相应的数据或者服务。服务器在收到请求后，会获取数据，对资源数据（比如数据库）进行加工处理，准备好响应，然后返回给客户端。

请求-响应模式是无状态的通信方式，每个完整的请求-响应都是相互独立的。进一步细分的话，它还可以分为同步和异步两种。你可以看下这张图片。

<img src="https://static001.geekbang.org/resource/image/6d/5d/6d3131d39d271c12aee82ddcf4a58a5d.jpg" alt="">

我们还是以外卖来举例。当你拿出手机点好外卖后，牛二楠家的服务员会收到外卖订单，然后通知厨师准备盖饭，同时另一个服务员已经熟练地打好了快乐水。

半个小时后，外卖小哥拿着装有你心仪午餐的袋子出现在公司门口，然后交到你的手里。他满脸笑容地说，闯了2个红绿灯才这么快送到，希望你给个好评。

这就是请求-响应模式。你是“客户端”，牛二楠家是“服务器”，你发出“请求”后，等待一段时间，然后外卖小哥将“响应”给到你。流程如下面的图片所示：

<img src="https://static001.geekbang.org/resource/image/16/ab/16aecc7c73a3bee6yyf3aae5897b8bab.jpg" alt="">

### HTTP

有哪些网络协议采用了请求-响应模式呢？HTTP 就是典型的代表。HTTP/2 协议还引入了异步请求-响应模式，客户端可以对请求设置不同的优先级，服务器可以根据优先级决定先响应哪个请求。

虽然 HTTP 协议的报文格式非常重，光是报文头就能达到 KB 大小，不太适合资源有限的嵌入式设备。但在一些计算资源和网络资源都比较充足的物联网设备上，HTTP协议仍然是一个可选项。而且它和现有的 **Web 系统**兼容，可以利用已有的 Web 服务器资源。

### CoAP

那么有没有跟 HTTP 协议类似，但是设计轻量，可以用于资源受限的物联网设备的协议呢？

有的，那就是 CoAP（Constrained Application Protocol）协议。

跟HTTP协议一样，CoAP 协议同样有 GET、POST、PUT、DELETE 等方法和响应状态码，同样使用 URI 而不是 Topic 来标识资源。

比如我们需要访问服务器 iotdemo.com 下面的 bedroom/temp 这个资源，那完整的资源地址是：

```
coap://iotdemo.com:5683/bedroom/temp 

```

CoAP 的消息采用二进制格式，支持可确认消息和不可确认消息两种QoS级别。可确认消息（Confirmable Message）与 MQTT 协议的QoS 1类似，不可确认消息（Non-confirmable Message）对应MQTT协议的 QoS 0级别。

另外，CoAP 协议基于的传输层协议是 UDP，而不是 HTTP 、 MQTT 协议的 TCP协议，所以对于设备的**计算资源要求更低**。传感器设备一般只需要上传数据，不用随时接收服务器的控制命令，这都说明 CoAP 协议适合电池供电的传感器设备。

### LwM2M

说完 CoAP，我再介绍一下跟它有关 LwM2M（Lightweight M2M）协议。

LwM2M 协议定义在 CoAP 协议之上，不过它在消息传输的基础上更进一步。因为它基于 IPSO （IP-base Smart Object）对设备模型进行了标准化，提供了一组轻量级设备管理和交互接口协议。

LwM2M 协议目前主要的实现是 C 语言的 Wakaama 和 Java 语言的 Leshan，相对来说应用还比较少。CoAP协议的应用场景同样适合 LwM2M协议，如果你希望在CoAP 协议的基础上更方便地实现**设备的管理**，可以考虑LwM2M协议。

## 通信模式的共存

到这里呢，我就讲完了“发布-订阅模式”和“请求-响应模式”的各自特点，以及相应的网络协议。那你可能会问，有没有网络协议可以同时拥有这两种通信模式呢？有这种想法，说明你非常善于独立思考。确实，这样也更能满足实际场景的需求，而且从原理上看，也完全可以实现共存。

现在行业内也意识到了这一点，所以一些网络协议已经纷纷做出了尝试。比如 MQTT 5.0中增加了请求-响应模式的新特性；AMQP 1.0版本也定义了请求-响应模式。而 CoAP协议呢，在新的初稿版本（Draft）中也增加了发布-订阅模式特性。

这种网络协议中的通信模式的共存，相比单一模式的设计都大大方便了具体场景中的应用，代表了一种网络协议的发展方向。

## 小结

在这一讲中，我对比了“发布-订阅”和“请求-响应”这两种主流的通信模式，并简单介绍了两种通信模式下的网络协议。

物联网应用是一个复杂的综合性系统，这要求你了解不同网络协议的功能特性和局限，并且为系统的不同部分做出合适的选择。这些选择原则，我总结为下面三点：

1. 物联网设备通常需要运行在网络不太可靠的环境中，而且在功耗、体积和计算资源方面也有诸多限制，所以我们在设备的开发中可以考虑使用MQTT和CoAP协议。
1. 云平台各服务之间需要快速、可靠地进行消息转发，这种情况可以选择 AMQP 协议。
1. 一些应用需要兼容 Web 系统的 RESTful 架构，比如通过 REST 开放物联网中的资源能力，供其他应用调用，这时 HTTP 和 CoAP 协议是合适的选择。

我在这里再提供一个网络协议的思维导图，供你参考。

<img src="https://static001.geekbang.org/resource/image/ff/81/ff230bbc7d6yy2c7c10e986f7dbe4581.jpg" alt="">

## 思考题

最后，我想给你留个问题。你还知道有哪些协议，适合用在物联网系统中吗？它们又是采用了哪种通信模式呢？

欢迎你在留言区写下你的答案，和我交流一下，也欢迎你将这一课分享给你的朋友，共同交流学习。
