PHP 也能开发物联网应用程序

通过抓包的方式来介绍和学习 MQTT 协议,结合真实存在的网络字节,让 PHP 程序猿不存在学习压力,循序渐进的了解熟悉 MQTT 协议

在 5G 时代的背景下,我们也将迎来一个万物互联的时代,习惯了平常的 Web 应用开发,学习一下物联网相关技术也是对自己技术一大提升。

PHP 作为脚本语言,官方定位是一个适合 Web 开发的语言,那么如何使用 PHP 开发一个物联网应用?

首先我们需要知道物联网中常用的一些通讯协议,例如MQTTModbusCoap等等。

这里我就以 MQTT 协议为例,讲解 PHP 如何来开发一个物联网应用?

PHP(“PHP: Hypertext Preprocessor”,超文本预处理器的字母缩写)是一种被广泛应用的开放源代码的多用途脚本语言,它可嵌入到 HTML 中,尤其适合 web 开发。

这句话是来自 PHP 官网,可见 PHP 官方对自己的定位就是 web 开发,但是尽管 PHP 的开发是以服务端脚本为目的,但事实上其功能远不局限与此…

它不但可以作为服务端脚本,也可以作为命令行脚本,当你在使用php -v查看 PHP 版本或者php -m查看安装的扩展时,这时你就在操作命令行脚本了。

了解过 Swoole 的小伙伴应该都知道:Swoole 的大部分功能只适用于 CLI 模式,也就是命令行脚本,在使用时就需要通过在命令中执行php index.php这种方式来运行。

而且 PHP 还能编写桌面应用程序,关于如何编写桌面应用程序这里就不过多说明,感兴趣的可以去 GitHub 或者谷歌了解一下。

那么现在都已经到了 2021 年,你还仅仅使用 PHP 来进行 CRUD 吗?没有其他什么能做了?答案当然是不!

在 Swoole 的加持之下,PHP 现在可以开发:即时通信(IM)、实时视频语音(WebRTC)、网络游戏(斗地主、五子棋、魔兽世界、传奇 2)以及物联网(MQTT),这些项目都可以在 GitHub 上找到。

既然要开发一个物联网项目,那么说到底什么是物联网?

物联网其实是互联网的一个延伸,互联网的终端是计算机(PC、服务器),我们运行的所有程序,无非都是计算机和网络中的数据处理和数据传输,除了计算机外,没有涉及任何其他的终端(硬件)。

物联网的本质还是互联网,只不过终端不再是计算机(PC、服务器),而是嵌入式计算机系统及其配套的传感器。

这是计算机科技发展的必然结果,为人类服务的计算机呈现出各种形态,如穿戴设备、环境监控设备、虚拟现实设备等等。

只要有硬件或产品连上网,发生数据交互,就叫物联网,万物相连的互联网。

那么 PHP 应该如何去开发物联网应用程序?

最常规的,也是对 PHP 程序员来说最简单的,首先就是后台模块,开发物联网项目的管理系统

这里就用到了 PHP 的 CRUD,开发起来也是很快的,例如:数据管理、报表管理、开关控制、设备管理、充值缴费等等,这些应该对于 PHP 程序员来说应该已经是得心应手了。

都说到这里了,也应该说一下重点了,那就是 PHP 如何进行 MQTT 协议解析来进行设备通讯交互呢?什么是 MQTT 协议?

什么是 MQTT 协议

MQTT 是一种基于发布/订阅(publish/subscribe)模式的"轻量级"通讯协议。

MQTT 协议是轻量、简单、开放和易于实现的,由于物联网的环境是非常特别的,所以 MQTT 遵循以下设计原则:

  • 发布/订阅(Pub/Sub)模式,方便消息在传感器之间传递;
  • 允许用户动态创建主题,零运维成本;
  • 把传输量降到最低以提高传输效率;
  • 把低带宽、高延迟、不稳定的网络等因素考虑在内;

PHP 需要处理 MQTT 协议解析,这就要使用到 Swoole 扩展,它提供了一个选项:open_mqtt_protocol,启用后会解析 MQTT 包头,Worker 进程的 onReceive 事件每次会返回一个完整的 MQTT 数据包。

Swoole Server 配置项

也可以使用原生 PHP 来自己进行解析包头包体,这里我们就直接基于 Swoole 来使用演示。

同时还会用到 PHP 内置的一些函数,例如:pack/unpackord/chr以及位运算等

使用pack/unpack来封包和解包,使用ord/chr来转换Ascii

在开始分析之前,推荐安装两个应用来方便我们进行测试:

一个是 Wireshark,用来进行网络分析、抓包,这样我们就可以明显的看到 MQTT 客户端发来的数据包;

Wireshark

另外一个是 MQTT 客户端,用来模拟硬件发送数据。

MQTTX

MQTT v3 的协议一共有 14 种报文类型,v5 有 15 种类型,增加了 AUTH 类型。

MQTT 报文类型

通过 MQTT 的协议文档我们可以了解到每个数据包的第一个字节就是协议类型,而第二字节则为剩余长度,那么我们就可以通过位运算和 ord 来获取每个包的报文类型和剩余长度

获取控制报文类型

如果剩余长度又是一个变长的编码,没有超过 128 的话,我们还可以这样获取,但是超过以后这样获取到是错误的数据

通过协议文档中的 C 示例代码,就可以转为使用 PHP 编写的代码:

剩余长度解析转换

这样我们就能正确获得到0268435455之间的剩余长度。

下面接着以第一个数据包类型 CONNECT 来作为说明,毕竟我们必须要先进行连接。

获取CONNECT报文

根据协议,在 CONNECT 包中,我们可以获取到以下数据:

  • Protocol Name 协议名称
  • Protocol Level 协议等级
  • Connect Flags 连接标志
  • Keep Alive 保持连接
  • Client ID 客户端 ID
  • Will Topic 遗嘱 topic
  • Will Message 遗嘱消息
  • User Name 用户名
  • Password 密码

在 Connect Flags 包含了一些 Flag 位,用于表示是否设置了用户名密码、遗嘱消息、清除会话、QoS 等级等

我们来试着使用代码来获取一下这些信息,需要注意的是MQTT协议为大端序,即高位在前。

协议名称为4个字节,协议等级为1个字节

获取协议名和协议级别

Connect Flags的数据包为1个字节,8个bit

Connect Flags

Keep Alive

CONNECT 数据包的有效载荷包含一个或多个带前缀的字段,这些字段的存在由变量头中的标志确定。

获取Payload

这些字段(如果存在)必须按客户端标识符,遗嘱主题,遗嘱消息,用户名,密码的顺序出现。

解析Payload

因为它们都是 utf-8 的字符串,所以我们可以封装一个方法来统一调用,减少了一部分重复代码。

这样我们就完成了一次 CONNECT 数据包的解析,在解析的时候会用到 unpack 和 ord,反之在封包的时候就会用到 pack 和 chr。

和对应的协议文档对应起来,似乎 MQTT 协议并没有那么困难,所以不要有压力,说自己搞不定…

当然你也可以直接使用我写的代码:simps/mqtt ,适用于 PHP 的 MQTT 协议解析和协程客户端,而且还是首个支持 MQTT v5.0 协议的 PHP 库。

支持 MQTT 协议 3.1、3.1.1 和 5.0 版本,支持QoS 0QoS 1QoS 2

以 CONNECT 数据包为例,证明 PHP 也可以使用 MQTT 协议来和设备通讯,当然不止这一个协议,Modbus等也可以,并且也有 PHP 的实现库。

在这里也向大家介绍一个能让 PHP 支持嵌入式开发的工具:PHPoC

PHPoC (PHP on Chip):是一个编程语言和一个物联网硬件开发平台。

PHPoC 是基于泛用脚本语言 PHP 开发的可编程语言。

PHPoC

PHPoC 基本与 PHP 兼容,但为了嵌入式系统开发增加了 I/O, UART, I2C, SPI, ADC, TIMER/COUNTER, RTC 等支持硬件接口及硬件控制的新函数及功能。

这样我们就能基于它来编写嵌入式程序,这样就更加丰富了 PHP 的生态能力,感兴趣的可以了解一下。

本文正在参加腾讯云加社区技术创作 101 训练营,阅读 PDF 可以访问【技术创作 101 训练营】PHP 也能开发物联网应用程序