使用LuatOS在Air780EPM上实现MQTT联网通信

通过LuatOS脚本语言,可在Air780EPM开发板上轻松实现MQTT通信功能,本文将详细讲解开发流程与关键代码实现。

一、MQTT 协议详解

1.1 什么是 MQTT?

MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议)是一种基于发布/订阅模式的轻量级通信协议。你可以把它想象成一个邮局系统:

发布者(Publisher):就像寄信的人,把消息发送到特定的“邮箱”(主题)。

订阅者(Subscriber):就像收信的人,他们事先告诉邮局(Broker)他们对哪些“邮箱”(主题)的信件感兴趣。

Broker(代理):就像邮局,负责接收发布者的消息,并根据订阅者的兴趣将消息分发给他们。

MQTT 协议由 IBM 在 1999 年开发,现在是 ISO 标准(ISO/IEC 20922),适用于物联网(IoT)和机器对机器(M2M)通信。

1.2 MQTT 的核心工作机制

1. 发布/订阅模式:
发布者(Publisher)将消息发送到特定的主题(Topic)。

订阅者(Subscriber)向 Broker 订阅感兴趣的主题。

Broker 负责将发布到主题的消息路由给所有订阅了该主题的客户端。

这种模式实现了发布者和订阅者的解耦,简单来说就是它们不需要知道彼此的存在。

2. 服务质量(QoS)等级:
QoS 0(最多一次):消息可能丢失,也可能因为网络层或中间件的意外重放而出现重复,但 MQTT 协议本身不会主动再发一次。适用于对可靠性要求不高的场景,如传感器数据。

QoS 1(至少一次):发送端会一直重试,直到收到接收端的 PUBACK 确认,因此消息至少送达一次,但也可能因确认丢失而被重复投递。适用于需要确保消息送达但可以容忍重复的场景。

QoS 2(只有一次):通过四步握手(PUBLISH → PUBREC → PUBREL → PUBCOMP)保证消息恰好送达一次;若任一步丢失,发送端会重传对应报文,直至整个流程完成,从而避免重复或丢失。适用于对消息可靠性要求极高的场景,如金融交易。

3. 轻量级设计:
MQTT 协议头最小只有 2 字节,非常适合网络带宽和设备资源有限的环境。

协议简单,易于实现,降低了开发成本。

1.3 MQTT 的主要优势

低带宽消耗:协议设计精简,有效减少网络流量。

低功耗:适用于电池供电的设备。

高可靠性:通过 QoS 机制保证消息传递的可靠性。

双向通信:支持设备间和设备与服务器间的双向通信。

多语言支持:支持多种编程语言,便于开发。

安全性强:支持用户名/密码和 SSL/TLS 加密,保障通信安全。

1.4 典型应用场景

智能家居:智能灯泡、智能插座、温控器等设备通过 MQTT 与家庭网关通信。

工业自动化:传感器数据采集、设备状态监控。

环境监测:气象站、水质监测站等远程数据收集。

车联网:车辆状态信息上报、远程控制指令下发。

医疗监控:远程病人监护设备数据传输。

二、演示功能概述

  1. 创建四路 mqtt 连接,详情如下

注意:代码中的 mqtt 服务器地址和端口会不定期重启或维护,仅能用作测试用途,不可商用,说不定哪一天就关闭了。用户开发项目时,需要替换为自己的商用服务器地址和端口。

创建一个 mqtt client,连接 mqtt server;

创建一个 mqtt ssl client,连接 mqtt ssl server,不做证书校验;

创建一个 mqtt ssl client,连接 mqtt ssl server,client 仅单向校验 server 的证书,server 不校验 client 的证书和密钥文件;

创建一个 mqtt ssl client,连接 mqtt ssl server,client 校验 server 的证书,server 校验 client 的证书和密钥文件;

  1. 每一路 mqtt 连接出现异常后,自动重连;

  2. 每一路 mqtt 连接,client 按照以下几种逻辑发送数据给 server

串口应用功能模块 uart_app.lua,通过 uart1 接收到串口数据,将串口数据增加 send from uart: 前缀后,使用 mobile.imei().."/uart/up" 主题,发送给 server;

定时器应用功能模块 timer_app.lua,定时产生数据,将数据增加 send from timer: 前缀后,使用 mobile.imei().."/timer/up" 主题,发送给 server;

  1. 每一路 mqtt 连接,client 收到 server 数据后,将数据增加 recv from mqtt/mqtt ssl/mqtt ssl ca/mqtt ssl mutual ca(四选一)server: 前缀后,通过 uart1 发送出去;

  2. 启动一个网络业务逻辑看门狗 task,用来监控网络环境,如果连续长时间工作不正常,重启整个软件系统;

  3. netdrv_device:配置连接外网使用的网卡,目前支持以下三种选择(三选一)

(1) netdrv_4g:4G 网卡

(2) netdrv_eth_spi:通过 SPI 外挂 CH390H 芯片的以太网卡

(3) netdrv_multiple:支持以上两种网卡,可以配置两种网卡的优先级

三、演示硬件环境

image

1、Air780EPM V1.3 版本开发板一块 + 可上网的 sim 卡一张 +4g 天线一根 + 网线一根:

sim 卡插入开发板的 sim 卡槽

天线装到开发板上

网线一端插入开发板网口,另外一端连接可以上外网的路由器网口

2、TYPE-C USB 数据线一根 + USB 转串口数据线一根,Air780EPM V1.3 版本开发板和数据线的硬件接线方式为:

Air780EPM V1.3 版本开发板通过 TYPE-C USB 口供电;(外部供电/USB 供电 拨动开关 拨到 USB 供电一端)

TYPE-C USB 数据线直接插到核心板的 TYPE-C USB 座子,另外一端连接电脑 USB 口;

USB 转串口数据线,一般来说,白线连接开发板的 UART1_TX,绿线连接开发板的 UART1_RX,黑线连接核心板的 GND,另外一端连接电脑 USB 口;

四、演示软件环境

4.1 软件环境

  1. 烧录工具:Luatools 下载调试工具

  2. 内核固件:Air780EPM V2012 版本固件(理论上,2025 年 8 月 10 日之后发布的固件都可以)

  3. 脚本文件:Air780EPM MQTT 脚本文件

  4. PC 端串口工具:例如 SSCOM、LLCOM 等都可以

  5. MQTT 客户端:MQTT 客户端软件 MQTTX

  6. LuatOS 运行所需要的 lib 文件:使用 Luatools 烧录时,勾选 添加默认 lib 选项,使用默认 lib 脚本文件。

准备好软件环境之后,接下来查看如何烧录项目文件到 Air780EPM 开发板中,将本篇文章中演示使用的项目文件烧录到 Air780EPM 开发板中。

4.2 API 介绍

sys 库:https://docs.openluat.com/osapi/core/sys/

libnet 库:https://docs.openluat.com/osapi/ext/libnet/

socket 库:https://docs.openluat.com/osapi/core/socket/

mqtt 库:https://docs.openluat.com/osapi/core/mqtt/

五、程序结构

carbon

5.1 文件说明

main.lua:主程序入口文件,负责初始化系统、启动网络驱动和 MQTT 客户端。

mqtt/:普通 MQTT 连接相关文件。

mqtt_main.lua:普通 MQTT 客户端的初始化和事件处理。

mqtt_receiver.lua:普通 MQTT 客户端的数据接收处理。

mqtt_sender.lua:普通 MQTT 客户端的数据发送队列管理。

mqtts/:MQTT SSL 连接(无证书校验)相关文件。

mqtts_main.lua:MQTT SSL 客户端的初始化和事件处理。

mqtts_receiver.lua:MQTT SSL 客户端的数据接收处理。

mqtts_sender.lua:MQTT SSL 客户端的数据发送队列管理。

mqtts_ca/:MQTT SSL 连接(单向证书校验)相关文件。

mqtts_ca_main.lua:MQTT SSL 单向证书校验客户端的初始化和事件处理。

mqtts_ca_receiver.lua:MQTT SSL 单向证书校验客户端的数据接收处理。

mqtts_ca_sender.lua:MQTT SSL 单向证书校验客户端的数据发送队列管理。

openluat_root_ca.crt:服务器 CA 证书文件。

sntp_app.lua:时间同步应用。

mqtts_mutual_ca/:MQTT SSL 连接(双向证书校验)相关文件。

mqtts_m_ca_main.lua:MQTT SSL 双向证书校验客户端的初始化和事件处理。

mqtts_m_ca_receiver.lua:MQTT SSL 双向证书校验客户端的数据接收处理。

mqtts_m_ca_sender.lua:MQTT SSL 双向证书校验客户端的数据发送队列管理。

airtest_client.crt:客户端证书文件。

airtest_client.key:客户端私钥文件。

openluat_root_ca.crt:服务器 CA 证书文件。

sntp_app.lua:时间同步应用。

netdrv/:网络驱动相关文件。

netdrv_4g.lua:4G 网络驱动。

netdrv_eth_spi.lua:SPI 以太网驱动。

netdrv_multiple.lua:多网络驱动管理。

netdrv_device.lua:网络设备配置文件。

network_watchdog.lua:网络环境检测看门狗。

timer_app.lua:定时器应用,用于生成测试数据。

uart_app.lua:串口应用,用于与 PC 端通信。

六、核心模块详解

6.1 主程序 (main.lua)

主程序文件 main.lua 是整个项目的入口点。它负责初始化系统环境。

6.1.1 初始化流程

1. 项目和版本定义:

定义PROJECT和VERSION变量。

2. 日志记录:

使用log.info("main", PROJECT, VERSION)在日志中打印项目名和版本号。

3. 看门狗初始化(如果支持):

配置并启动硬件看门狗,防止程序死循环卡死。

4. 加载功能模块:

加载网络环境检测看门狗模块(network_watchdog)。

加载网络驱动设备模块(netdrv_device)。

加载串口应用模块(uart_app)。

加载定时器应用模块(timer_app)。

加载MQTT客户端主模块(mqtt_main)。

加载MQTT SSL客户端主模块(mqtts_main、mqtts_ca_main、mqtts_m_ca_main)。

5. 启动任务调度器:

调用sys.run()启动LuatOS的任务调度器,开始执行各个任务。

carbon (1)

6.2 网络驱动 (netdrv/)

网络驱动模块负责初始化和管理不同的网络连接方式,如 4G 和以太网。

6.2.1 4G 网络驱动 (netdrv_4g.lua)

监听 IP_READY 和 IP_LOSE 消息,监控网络连接状态。

设置默认网卡为 socket.LWIP_GP。

carbon (2)

6.2.2 以太网网络驱动(netdrv_eth_spi.lua)

通过 SPI 接口外挂 CH390H 芯片实现以太网。

通过控制 GPIO20 引脚使能芯片供电。

配置 SPI1 接口参数,用于与 CH390H 芯片通信。

通过 netdrv.setup 函数配置以太网卡,并开启 DHCP 动态获取 IP 地址。

设置默认网卡为 socket.LWIP_ETH。

carbon (3)

6.2.3 多网络驱动管理 (netdrv_multiple.lua)

管理多个网络驱动实例,根据配置选择合适的网络连接方式。

通过 exnetif.set_priority_order 函数配置多网卡的控制参数以及优先级。

通过 exnetif.notify_status 函数设置网卡状态变化通知回调函数。

carbon (4)

6.3 MQTT 客户端 (mqtt/, mqtts/, mqtts_ca/, mqtts_mutual_ca/)

每个 MQTT 客户端目录都包含三个核心文件:_main.lua、_receiver.lua 和 _sender.lua,分别负责客户端的初始化、数据接收和数据发送。

6.3.1 客户端初始化 (_main.lua)

注意:代码中的 mqtt 服务器地址和端口会不定期重启或维护,仅能用作测试用途,不可商用,说不定哪一天就关闭了。用户开发项目时,需要替换为自己的商用服务器地址和端口。

创建 MQTT 客户端对象,配置服务器地址、端口、客户端 ID、用户名、密码等参数。

设置事件回调函数,处理连接、订阅、接收和异常等事件。

启动客户端任务,开始连接 MQTT 服务器。

6.3.2 数据接收 (_receiver.lua)

实现 proc 函数,处理接收到的数据。

打印接收到的数据内容。

通过 sys.publish("FEED_NETWORK_WATCHDOG") 触发网络看门狗喂狗。

6.3.3 数据发送 (_sender.lua)

实现 send 函数,将数据添加到发送队列。

管理发送队列,按顺序发送数据。

支持 QoS 配置和发送结果回调。

6.4 应用功能 (timer_app.lua, uart_app.lua)

应用功能模块负责生成测试数据和处理串口通信。

6.4.1 定时器应用 (timer_app.lua)

创建一个 5 秒循环的定时器。

定时生成递增的测试数据。

通过 sys.publish("SEND_DATA_REQ", data) 发布发送请求消息。

实现发送结果回调,根据发送结果决定是否重发数据。

carbon (5)

6.4.2 串口应用 (uart_app.lua)

配置 UART1,波特率为 115200。

接收来自 PC 的数据,并通过 MQTT 发送。

将 MQTT 接收到的数据通过串口输出到 PC。

实现数据缓冲和超时处理。

carbon (6)

6.5 网络环境检测看门狗 (network_watchdog.lua)

网络看门狗模块负责监控网络连接状态和数据收发情况,确保系统在网络异常时能够自动恢复。

6.5.1 设计原则

看门狗超时时间应大于任意一个 MQTT 连接的发送间隔。

通过接收 FEED_NETWORK_WATCHDOG 消息来喂狗。

超时未收到喂狗消息时,系统自动重启。

6.5.2 实现细节

创建 network_watchdog_task_func 任务函数。

任务函数循环等待 FEED_NETWORK_WATCHDOG 消息,超时时间为 5 分钟。

超时则调用 sys.restart("network timeout") 重启系统。

carbon (7)

6.6 SSL 连接实现

项目展示了三种不同的 SSL 连接实现方式,满足不同安全等级的需求。

6.6.1 无证书校验 (mqtts/)

在创建 MQTT 客户端时,设置 ssl 参数为 true。

不进行服务器证书校验,适用于对安全性要求不高的场景。

6.6.2 单向证书校验 (mqtts_ca/)

加载服务器 CA 证书文件 openluat_root_ca.crt。

在创建 MQTT 客户端时,配置 ssl 参数,指定 CA 证书路径。

依赖 sntp_app.lua 同步系统时间,以验证证书有效期。

6.6.3 双向证书校验 (mqtts_mutual_ca/)

同时加载服务器 CA 证书、客户端证书和客户端私钥。

在创建 MQTT 客户端时,配置 ssl 参数,指定所有证书和密钥的路径。

使用特定端口(8886)进行连接。

七、系统与用户消息类型

7.1 系统消息

IP_READY:网络 IP 地址已准备好。

IP_LOSE:网络 IP 地址丢失。

NTP_UPDATE:SNTP 时间同步完成。

7.2 用户消息

RECV_DATA_FROM_SERVER:从 MQTT 服务器接收到数据。

SEND_DATA_REQ:请求发送数据。

FEED_NETWORK_WATCHDOG:网络看门狗喂狗消息。

八、演示功能

8.1 准备工作

8.1.1 MQTT 客户端建立

MQTT 客户端测试工具:MQTT 客户端软件 MQTTX

(1)创建一个 MQTT 客户端

这里我使用测试服务器(lbsmqtt.airm2m.com:1884)进行建立,大家一定不要将测试服务器用于正式批量的项目中。

image

(2)设置发布/订阅主题

在设置发布/订阅主题时,主题格式一定要根据要求来写,否则会出现数据无法通信的情况。

image

8.1.2 MQTT SSL 客户端建立(无证书校验、单向认证)

MQTT 客户端测试工具:MQTT 客户端软件 MQTTX

(1)创建一个 MQTT 客户端

这里我使用测试服务器(airtest.openluat.com:8888)进行建立,大家一定不要将测试服务器用于正式批量的项目中。 无证书校验、单向认证使用的是同一个域名端口,在 MQTTX 工具上创建客户端只是用于与 Air780EPM 建立的 MQTT 客户端进行数据通信,因此这时候可以在 MQTTX 工具上只建立一个 MQTT SSL 客户端。

image

(2)设置发布/订阅主题

在设置发布/订阅主题时,主题格式一定要根据要求来写,否则会出现数据无法通信的情况。

image

8.1.3 MQTT SSL 客户端建立(双向认证)

MQTT 客户端测试工具:MQTT 客户端软件 MQTTX

(1)创建一个 MQTT 客户端

这里我使用测试服务器(airtest.openluat.com:8886)进行建立,大家一定不要将测试服务器用于正式批量的项目中。

image

(2)设置发布/订阅主题

在设置发布/订阅主题时,主题格式一定要根据要求来写,否则会出现数据无法通信的情况。

image

8.2 不同网卡切换

Air780EPM 模组支持单 4g 网卡,单 spi 以太网卡,多网卡。

切换网卡为 4G 网卡:

在 netdrv_device.lua 模块里只打开 netdrv_4g 模块。netdrv_4g.lua 模块中的代码不需要修改。

image

LuaTools 工具日志打印:

如下图所示,如出现类似 I/user.netdrv_4g.ip_ready_func IP_READY 10.63.142.199 255.255.255.255 0.0.0.0 nil 的日志,则表示 4g 网卡连接成功。

image

切换网卡为以太网卡:

注意:Air780EPM 的以太网卡是通过 SPI 外挂 CH390H 芯片实现的。

在 netdrv_device.lua 模块里只打开 netdrv_eth_spi 模块。如果是使用官方的开发板,netdrv_eth_spi 模块中的代码不需要修改。

image

luatools 日志打印:

如出现类似 I/user.netdrv_eth_spi.ip_ready_func IP_READY 192.168.0.168 255.255.255.0 192.168.0.1 nil 的日志,则表示以太网卡联网成功。

image

多网卡自动切换:

可根据自己的需求调整网卡的优先级,以下示例设置为以太网卡是最高优先级。

首先在 netdrv_device.lua 文件中只打开 netdrv_multiple 模块。

image

默认以太网卡进行连接

image

拔掉网线后,网络切换为 4g 网卡

image

8.3 MQTT 通信实操

MQTT 客户端数据发送与接收:

下图为 Air780EPM 模组建立的 MQTT 客户端通过指定主题向其他同域名端口的 MQTT 客户端发送数据成功后的日志打印。

image

如下图在 MQTTX 测试工具上建立相同域名端口的 MQTT 客户端(Client ID 需要不一致),通过订阅指定主题,可以接收到其他同域名端口的 MQTT客户端 通过该指定主题发送的数据。

image

如下图所示,通过 MQTTX 测试工具上建立的 MQTT 客户端向指定主题发送一个数据。

image

模组端在建立同域名端口的 MQTT 客户端后,在代码中还订阅了指定主题,因此 MQTTX 测试工具上建立的同域名端口的 MQTT 客户端通过指定主题发送数据时,模组端建立的同域名端口的 MQTT 客户端可以接收到这个数据,并在代码中做了处理,从而让其显示在 LuaTools 工具上。

image

在 PC 端使用串口工具发送数据给 Air780EPM,Air780EPM 内部会将接收到的数据通过建立的同域名端口的 MQTT 客户端按照指定主题转发出去,MQTTX 测试工具建立的同域名端口的 MQTT 客户端通过订阅这个指定主题可以接收到 Air780EPM 转发出去的数据。

image

在 MQTTX 测试工具建立的同域名端口的 MQTT 客户端,通过指定主题发送数据后,Air780EPM 模组建立的同域名端口的 MQTT 客户端通过订阅该指定主题后可以接收到数据,并将数据通过 UART 转发给 PC 端串口工具。

image

MQTT SSL 客户端(无证书校验)数据发送与接收:

下图为 Air780EPM 模组建立的 MQTT SSL 客户端(无证书校验)通过指定主题向其他同域名端口的 MQTT SSL 客户端发送数据成功后的日志打印。

image

如下图在 MQTTX 测试工具上建立相域名端口的 MQTT SSL 客户端(Client ID 需要不一致),通过订阅指定主题,可以接收到其他同域名端口的 MQTT SSL 客户通过该指定主题发送的数据。

image

如下图所示,通过 MQTTX 测试工具建立的同域名端口的 MQTT SSL 客户端向指定主题发送一个数据。
image

模组端在建立同域名端口 MQTT SSL 客户端(无证书校验)后,在代码中订阅了这个指定主题,因此当 MQTTX 测试工具建立的同域名端口的 MQTT SSL 客户端通过指定主题发送数据时,模组端建立的同域名端口的 MQTT SSL 客户端(无证书校验)可以接收到这个数据,并在代码中做了处理,从而让其显示在 LuaTools 工具上。

image

在 PC 端使用串口工具发送数据给 Air780EPM,Air780EPM 内部会将接收到的数据通过建立的同域名端口 MQTT SSL 客户端(无证书校验)按照指定主题转发出去,MQTTX 测试工具建立的同域名端口的 MQTT SSL 客户端通过订阅这个指定主题可以接收到 Air780EPM 转发出去的数据。

image

在 MQTTX 测试工具建立的同域名端口的 MQTT SSL 客户端(无证书校验)通过指定主题发送数据后,Air780EPM 模组建立的同域名端口的 MQTT SSL 客户端(无证书校验)通过订阅该指定主题后可以接收到数据,并将数据通过 UART 转发给 PC 端串口工具。
image

MQTT SSL 客户端(单向认证)数据发送与接收

下图为 Air780EPM 模组建立的 MQTT SSL 客户端(单向认证)通过指定主题向其他同域名端口的 MQTT 客户端发送数据成功后的日志打印。

image

如下图在 MQTTX 测试工具上建立同域名端口的 MQTT SSL 客户端(Client ID 需要不一致),通过订阅指定主题,可以接收到其他同域名端口的 MQTT SSL 客户通过该主题发送的数据。

image

如下图所示,通过 MQTTX 测试工具建立的同域名端口的 MQTT SSL 客户端(单向认证)向指定主题发送一个数据。

image

模组端在建立同域名端口 MQTT SSL 客户端(单向认证)后,在代码中还订阅了指定主题,因此当 MQTTX 测试工具建立的同域名端口的 MQTT SSL 客户端通过指定主题发送数据时,模组端建立的同域名端口的 MQTT SSL 客户端(单向认证)可以接收到这个数据,并在代码中做了处理,从而让其显示在 LuaTools 工具上。

image

在 PC 端使用串口工具发送数据给 Air780EPM,Air780EPM 内部会将接收到的数据通过建立的同域名端口的 MQTT SSL 客户端(单向认证)按照指定主题转发出去,MQTTX 测试工具建立的同域名端口的 MQTT SSL 客户端通过订阅这个指定主题可以接收到 Air780EPM 转发出去的数据。

image

在 MQTTX 测试工具建立的同域名端口的 MQTT SSL 客户端(单向认证)通过指定主题发送数据后,Air780EPM 模组建立的同域名端口的 MQTT SSL 客户端(单向认证)通过订阅该指定主题后可以接收到数据,并将数据通过 UART 转发给 PC 端串口工具。
image

MQTT SSL 客户端(双向认证)数据发送与接收

下图为 Air780EPM 模组建立的 MQTT SSL 客户端(双向认证)通过指定主题向其他同域名端口的 MQTT SSL 客户端发送数据成功后的日志打印。

image

如下图在 MQTTX 测试工具上建立同域名端口的 MQTT 客户端(Client ID 需要不一致),通过订阅指定主题,可以接收到其他同域名端口的 MQTT 客户端通过该主题发送的数据。

image

如下图所示,通过 MQTTX 测试工具建立的同域名端口的 MQTT SSL 客户端向指定主题发送一个数据。

image

模组端在建立同域名端口 MQTT SSL 客户端(双向认证)后,在代码中还订阅了指定主题,因此当 MQTTX 测试工具建立的同域名端口的 MQTT SSL 客户端通过指定主题发送数据时,模组端建立的同域名端口的 MQTT SSL 客户端(双向认证)可以接收到这个数据,并在代码中做了处理,从而让其显示在 LuaTools 工具上。

image

在 PC 端使用串口工具发送数据给 Air780EPM,Air780EPM 内部会将接收到的数据通过建立的 MQTT SSL 客户端(双向认证)按照指定主题转发出去,MQTTX 测试工具建立的同域名端口的 MQTT SSL 客户端通过订阅这个指定主题可以接收到 Air780EPM 转发出去的数据。

image

在 MQTTX 测试工具建立的同域名端口的 MQTT SSL 客户端(双向认证)通过指定主题发送数据后,Air780EPM 模组建立的同域名端口的 MQTT SSL 客户端(双向认证)通过订阅该指定主题后可以接收到数据,并将数据通过 UART 转发给 PC 端串口工具。

image

九、总结

至此,我们演示了使用不同网卡进行 MQTT 通信的全过程,相信聪明的你已经完全领悟 MQTT 通信的逻辑了,快来实际操作一下吧!

posted @ 2025-09-29 14:55  电子老师傅  阅读(58)  评论(0)    收藏  举报