【MQTT】使用MQTT上报温度阿里云

article/2025/7/7 1:23:57

MQTT上报温度到阿里云

    • 前言
    • iniparser配置文件
    • cJSON
    • sqlite3数据库
    • 流程图
    • 配置信息
    • 发布端代码实现
    • 运行结果

前言

在上几篇文章中我们用MQTT.fx模拟客户端实现了与阿里云物联网平台的双向通信,接下来我们自己动手编程使用mosquitto库实现一个发布端。

iniparser配置文件

iniparser介绍
与阿里云进行通信时,我们需要如下一些信息,例如在使用MQTT.fx时:
在这里插入图片描述
阿里云配置和MQTT.fx使用
在上篇文章中阿里云配置文件另外之前发布和订阅的topic也要记下来:
在这里插入图片描述
这些都是我们在项目中要用到的配置信息,具体应用在:

#客户端id
clientid:
struct mosquitto *mosquitto_new( const char * id, bool clean_session, void * obj )
#连接阿里云的端口,主机名
brokeraddress and brokerport:
int mosquitto_connect( struct mosquitto * mosq, const char * host, int port, int keepalive )
#连接阿里云账号和密码
username and password:
int mosquitto_username_pw_set(struct mosquitto * mosq, const char *username, const char *password )
#订阅的主题
topic:
int mosquitto_publish( struct mosquitto * mosq, int * mid, const char * topic, int payloadlen, const void * payload, int qos, bool retain )

当然可以直接写死在代码里,但是这样一来,代码复用性不高,换一个设备那么就要改一次源码来更改设备配置信息。MQTT主机使用可以看这篇博客.

所以我们写一个.ini文件,这样当我们更换设备的时候只需要修改这个.ini文件中的信息即可。然后在代码中使用iniparser库中API。

cJSON

JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。

阿里云上payload must be json format 负载(消息)必须为cJSON格式。
因为使用的阿里云提供的标准物模型,所以消息格式应该遵循阿里云的规范。这就是我们要使用cJSON的原因。

要是已其他格式发送,阿里云收到了消息,但是因为参数不匹配,无法对消息进行解析,也就无法获取到温度消息
学习cJSON可以参考博客

sqlite3数据库

SQLite是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。它是一个零配置的数据库,这意味着与其他数据库不一样,您不需要在系统中配置。
就像其他数据库,SQLite 引擎不是一个独立的进程,可以按应用程序需求进行静态或动态连接。SQLite 直接访问其存储文件。

sqlite3数据库优点

1.不需要一个单独的服务器进程或操作的系统(无服务器的)。
2.SQLite 不需要配置,这意味着不需要安装或管理。
3. 一个完整的 SQLite数据库是存储在一个单一的跨平台的磁盘文件。
4. SQLite 是非常小的,是轻量级的,完全配置时小于 400KiB,省略可选功能配置时小于250KiB。
5.SQLite 是自给自足的,这意味着不需要任何外部的依赖。
6 SQLite 事务是完全兼容ACID 的,允许从多个进程或线程安全访问。
7.SQLite 支持 SQL92(SQL2)标准的大多数查询语言的功能。
8. SQLite 使用ANSI-C 编写的,并提供了简单和易于使用的 API。
9. SQLite 可在 UNIX(Linux, Mac OS-X, Android,iOS)和 Windows(Win32, WinCE, WinRT)中运行。

sqlite3库函数

流程图

在这里插入图片描述

配置信息

#include "iniparser.h"
#include "mqtt_conf.h"
#include <stdio.h>
#include <string.h>/* 载入设置参数 */
int get_config(char *path,mqtt_user_data *mqtt,int mode)
{dictionary      *ini = NULL;const char      *brokeraddress;int             brokerport;const char      *username;const char      *password;const char      *clientid;const char      *topic;int             Qos;const char      *method;const char      *time;const char      *jsonid;const char      *identifier;const char      *version;if(!path || !mqtt){printf("invalid_argument: %s\n",__FUNCTION__);return -1;}ini = iniparser_load(path);if(!ini){printf("iniparser_load failed!\n");return -1;}brokeraddress = iniparser_getstring(ini,"address:host",DEFAULT_BROKER_ADDRESS);brokerport= iniparser_getint(ini,"address:port",DEFAULT_BROKER_PORT);username = iniparser_getstring(ini,"user_name_pwd:username",DEFAULT_USERNAME);password = iniparser_getstring(ini,"user_name_pwd:pwd",DEFAULT_PASSWORD);clientid = iniparser_getstring(ini,"clientid:id",DEFAULT_CLIENTID);identifier = iniparser_getstring(ini,"ali_json:identifier",DEFAULT_JSONID);if(mode == SUB){topic = iniparser_getstring(ini,"sub_topic:topic",DEFAULT_SUB_TOPIC);}else if(mode == PUB){topic = iniparser_getstring(ini,"pub_topic:topic",DEFAULT_PUB_TOPIC);method = iniparser_getstring(ini,"ali_json:method",DEFAULT_METHOD);//time = iniparser_getstring(ini,"ali_time:time",DEFAULT_TIME);//jsonid = iniparser_getstring(ini,"ali_json:id",DEFAULT_JSONID);version = iniparser_getstring(ini,"ali_json:version",DEFAULT_VERSION);}else if(mode != SUB && mode != PUB){printf("invalid_argument : %s mode!\n",__FUNCTION__);return -1;}strncpy(mqtt->brokeraddress,brokeraddress,SIZE);mqtt->brokerport = brokerport;mqtt->Qos        = Qos;strncpy(mqtt->username,username,SIZE);strncpy(mqtt->password,password,SIZE);strncpy(mqtt->clientid,clientid,SIZE);strncpy(mqtt->topic,topic,SIZE);          strncpy(mqtt->identifier,identifier,SIZE);if(mode == PUB){strncpy(mqtt->method,method,SIZE);//strncpy(mqtt->time,time,SIZE);//strncpy(mqtt->jsonid,jsonid,SIZE);strncpy(mqtt->version,version,SIZE);}iniparser_freedict(ini);return 0;}
#ifndef MQTT_CONF_H
#define MQTT_CONF_H#define  SIZE                1024
#define KEEP_ALIVE          60enum{SUB ,PUB
};typedef struct mqtt_user_data
{char    brokeraddress[SIZE] ;int     brokerport;char    username[SIZE];char    password[SIZE];char    clientid[SIZE];char    topic[SIZE];int     Qos;char    method[SIZE] ;char    time[SIZE];char    jsonid[SIZE] ;char    identifier[SIZE] ;char    version[SIZE] ;}mqtt_user_data;int set_config(char *path,char *host,int port, char *clientid,char *uname,char *pwd,char *topic);int get_config(char *path, mqtt_user_data *mqtt, int mode);#endif
[address]
host    =       iot-06z00i99uliom9a.mqtt.iothub.aliyuncs.com
port    =       1883[user_name_pwd]
username    =   ds18b20&gr71iZ9S48c
pwd         =   2a59fde4b9765b403df5bfe7ce63b06cfb79e7d57cb373a0dfa501f79623cc83[clientid]
id          =    gr71iZ9S48c.ds18b20|securemode=2,signmethod=hmacsha256,timestamp=2524608000000|[pub_topic]
topic       =   /sys/gr71iZ9S48c/ds18b20/thing/event/property/post[sub_topic]
topic       =   /sys/gr71iZ9S48c/ds18b20/thing/service/property/set[ali_json]
method      =   thing.service.property.set
id          =   ip    
identifier  =   CurrentTemperature
version     =   1.0.0[KEEP_ALIVE]
alive   =   60[ali_Qos]
Qos     =   0

发布端代码实现

#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <libgen.h>
#include <getopt.h>
#include <string.h>
#include <mosquitto.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <signal.h>
#include <time.h>#include "mqtt_conf.h"
#include "cJSON.h"
#include "dictionary.h"
#include "iniparser.h"
#include "ifconfig.h"
#include "db_sqlite3.h"#define  PROG_VERSION "1.0.0"
#define  INI_PATH "./mqtt_aliyun.ini"static int g_stop = 0;/* 调用信号 */
void sig_handler(int sig_num)
{if(sig_num == SIGUSR1)g_stop = 1;}int db_init(sqlite3  *db,char *zErrMsg);
int db_table(char *zErrMsg, sqlite3 *db);
int db_store(sqlite3 *db,char *zErrMsg);
int get_temperature(float *temper);
int get_time (char *datetime,int len);
static inline void print_usage(char *progname);
char *create_json(void *obj);
void connect_callback(struct mosquitto *mosq,void *obj,int rc);int main (int argc, char **argv)
{char                        *progname = basename(argv[0]);int                         brokerport = 1883;char                        *brokeraddress = NULL;char                        *clientid = NULL;char                        *username = NULL;char                        *password = NULL;char                        *topic = NULL;struct mosquitto            *mosq = NULL;int                         daemon_run = 0;int                         opt = -1;int                         rv;int                         log_fd;struct mqtt_user_data       mqtt;struct option options[] = {{"daemon",no_argument,NULL,'d'},{"topic", required_argument,NULL,'t'},{"brokeraddress", required_argument,NULL,'H'},{"clientid", required_argument, NULL, 'i'},{"brokerport",required_argument,NULL,'p'},{"help",no_argument,NULL,'h'},{"username",required_argument,NULL,'u'},{"password",required_argument,NULL,'P'},{NULL,0,NULL,0}};while((opt = getopt_long(argc,argv,"dhp:t:i:u:P:H:",options,NULL)) != -1){switch(opt){case 't':topic = optarg;break;case 'i':clientid = optarg;break;case 'H':brokeraddress = optarg;break;case 'u':username = optarg;break;case 'P':password = optarg;break;case 'd':daemon_run = 1;break;case 'p':brokerport = atoi(optarg);break;case 'h':print_usage(argv[0]);return 0;default:break;}}/* 创建日志 */if(daemon_run){printf("program %s running in backgrund\n", progname);if( (log_fd = open("client.log", O_CREAT|O_RDWR, 0666)) < 0){printf("open() failed:%s\n", strerror(errno)) ;return -2;}dup2(log_fd, STDOUT_FILENO);dup2(log_fd, STDERR_FILENO);daemon(1,1);}/* 安装信号 */signal(SIGUSR1,sig_handler);/* 载入配置文件 */memset(&mqtt,0,sizeof(mqtt));rv = get_config(INI_PATH,&mqtt,PUB);/* MQTT 初始化 */mosquitto_lib_init();/* 创建MQTT 客户端 */mosq = mosquitto_new(mqtt.clientid,true,(void *)&mqtt);if(!mosq){printf("mosquitto_new() failed: %s\n",strerror(errno));goto cleanup;return -1;}/* 设置账号密码 */if(mosquitto_username_pw_set(mosq,mqtt.username,mqtt.password) != MOSQ_ERR_SUCCESS){printf("mosquitto_username_pw_set failed: %s\n",strerror(errno));goto cleanup;}printf("Create mosquitto successfully!\n");/* 回调函数 */mosquitto_connect_callback_set(mosq,connect_callback);while(!g_stop){/* 连接MQTT服务器,ip,端口,时间 */ if(mosquitto_connect(mosq, mqtt.brokeraddress,mqtt.brokerport,KEEP_ALIVE) != MOSQ_ERR_SUCCESS){printf("mosquitto_connect() failed: %s\n",strerror(errno));goto cleanup;}printf("connect successfully\n");/*无阻塞 断线连接 */mosquitto_loop_forever(mosq,-1,1);sleep(3);}/* 释放客户端,清除 */
cleanup:close(log_fd);mosquitto_destroy(mosq);mosquitto_lib_cleanup();return 0;
} /* 帮助信息 */
void print_usage(char *progname)
{printf("%s usage:\n",progname);printf("Example: %s -h ${brokeraddress} -p ${brokerport} -i ${clientid} -u ${username} -p ${password} -t${topic} -h ${help} -d ${daemon}\n",progname);printf("-h(--host): sepcify brokeraddress.\n");printf("-p(--port): sepcify brokerport.\n");printf("-h(--Help): print this help information.\n");printf("-d(--daemon): set program running on background.\n");printf("-i(--clientid): sepcify the clientid.\n");printf("-u(--username): sepcify username of the client.\n");printf("-p(--password): sepcify password of the username.\n");printf("-t(--topic): sepcify topic of the client.\n");printf("-d(--daemon): running in backgrund.\n");
}/* cJSON打包数据 */
void connect_callback(struct mosquitto *mosq,void *obj,int rc)
{char                    ipaddr[16];char                    *interface="eth0";char                    datetime[64];cJSON                   *root;cJSON                   *item;char                    *msg;struct mqtt_user_data   *mqtt;char                    buf[2048];printf("Connection successful cJSON call packaging\n");float temper = 0.00000000;if(get_temperature(&temper) < 0){printf("get_temperature failed.\n");return;}if(get_time(datetime,sizeof(datetime))<0){printf("get_time failure\n");return ;}memset(ipaddr,0,sizeof(ipaddr));if(get_ipaddr(interface,ipaddr,sizeof(ipaddr))<0){printf("ERROR:get ip address failure\n");return ;}snprintf(buf,sizeof(buf),"%s/%s/%f",ipaddr,datetime,temper);sqlite_tem(buf);printf("Data transfer database successfully!\n");printf("\n");root = cJSON_CreateObject();item = cJSON_CreateObject();if(!obj){printf("invalid_argument in %s\n",__FUNCTION__);return;}mqtt = (mqtt_user_data *)obj;cJSON_AddItemToObject(root,"method",cJSON_CreateString(mqtt->method));cJSON_AddItemToObject(root,"id",cJSON_CreateString(ipaddr));cJSON_AddItemToObject(root,"time",cJSON_CreateString(datetime));cJSON_AddItemToObject(root,"params",item);cJSON_AddItemToObject(item,"CurrentTemperature",cJSON_CreateNumber(temper));cJSON_AddItemToObject(root,"version",cJSON_CreateString(mqtt->version));msg = cJSON_Print(root);printf("%s\n",msg);if(!rc){if(mosquitto_publish(mosq,NULL,mqtt->topic,strlen(msg),msg,mqtt->Qos,NULL) != MOSQ_ERR_SUCCESS){printf("mosquitto_publish failed: %s\n",strerror(errno));return;}}mosquitto_disconnect(mosq);}/* 获取温度 */
int get_temperature(float *temper)
{char            w1_path[64] = "/sys/bus/w1/devices/";char            chip[32];char            buf[128];DIR            *dirp;struct dirent  *direntp;int             fd = -1;char           *ptr;int             found = 0;if( !temper ){return -1;}if((dirp = opendir(w1_path)) == NULL){printf("Opendir '%s' error: %s\n", w1_path, strerror(errno));return -2;}while((direntp = readdir(dirp)) != NULL){if(strstr(direntp->d_name,"28-")){strncpy(chip, direntp->d_name, sizeof(chip));found = 1;break;}}closedir(dirp);if( !found ){printf("Can not find ds18b20 in '%s'\n", w1_path);return -3;}strncat(w1_path, chip, sizeof(w1_path)-strlen(w1_path));strncat(w1_path, "/w1_slave", sizeof(w1_path)-strlen(w1_path));if( (fd=open(w1_path, O_RDONLY)) < 0 ) { printf("open %s error: %s\n", w1_path, strerror(errno)); return -4;} if(read(fd, buf, sizeof(buf)) < 0){printf("read %s error: %s\n", w1_path, strerror(errno)); return -5;} ptr = strstr(buf, "t=");if( !ptr ){printf("ERROR: Can not get temperature\n");return -6;}*temper = atof(ptr+=2)/1000;close(fd);return 0;
}/* 获取时间 */
int get_time(char *datime,int len)
{time_t          t;struct tm       *p;time(&t);p = gmtime(&t);snprintf(datime, 32, "%d-%d-%d %d:%d:%d", 1900+p->tm_year,1+p->tm_mon, p->tm_mday, (p->tm_hour + 8), p->tm_min, p->tm_sec);return 0 ;
}

运行结果

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
可以看到温度在实时更新(我设置睡眠时间短,所有没有显示,温度变化).

项目源码地址


http://chatgpt.dhexx.cn/article/Md4oOPbP.shtml

相关文章

实现跨越多个云的无缝云数据管理

By Jeffrey - 资深IT经理人&#xff0c;IT运营和安全顾问&#xff0c;历任多家知名跨国企业包括麦肯锡大中华区、通用电气公司、壳牌石油、英美烟草等公司IT总经理 云已经不是一个新鲜话题&#xff0c;越来越多企业甚至个人已经将数据搬到了云上&#xff0c;享受云带来的便捷&a…

腾讯云运维工程师认证TCA--真题(最新2022.11)

腾讯云运维工程师认证TCA题库&#xff0c;覆盖95%题目。 1、TSF控制台的配置中心&#xff0c;目前支持以下哪一种格式的配置文件? JSON格式XML格式YAML格式Properties配置格式 正确答案&#xff1a;C 解答&#xff1a;无 2、传统应用开发采用瀑布开发模型&#xff0c;瀑布开…

基于OpenPCDet框架的基线模型下载及性能评估

基于OpenPCDet框架的基线模型下载及性能评估 W.P. Xiao, Vision group&#xff0c;SHUSV 版本更新时间更新内容作者1V 1.02021.12更新基线模型W.P. Xiao, Y.Q. Wu2 目录 文章目录 基于OpenPCDet框架的基线模型下载及性能评估基线模型权重下载基线模型性能PointPillarSECONDSECO…

GPT2中文模型本地搭建(二)

GPT2中文模型本地搭建&#xff08;二&#xff09; 1、简单介绍1.1 bert4keras是什么&#xff0c;与Keras有什么关系&#xff1f;1.2 常用的预训练模型加载框架有几种&#xff1f;1.3 预训练模型常见版本 2、GPT2-ML 开源中文模型本地搭建2.1 开发环境准备2.2 下载代码2.3 下载模…

阿里云ECS服务器部署

阿里云ECS体验JavaWeb 基础步骤其他操作 第一章 基础步骤 第01节 登录阿里云服务器 在购买ECS服务器后&#xff0c;系统会创建一个ECS实例。每一个ECS实例对应一台已购买的云服务器。 您可以通过电脑上自带的终端工具访问云服务器&#xff0c;进行应用部署和环境搭建。 1. …

AI 框架部署方案之模型部署概述

0 概述 模型训练重点关注的是如何通过训练策略来得到一个性能更好的模型&#xff0c;其过程似乎包含着各种“玄学”&#xff0c;被戏称为“炼丹”。整个流程包含从训练样本的获取&#xff08;包括数据采集与标注&#xff09;&#xff0c;模型结构的确定&#xff0c;损失函数和评…

调用百度云语音转文本

文章目录 一、创建应用二、调用方式一三、调用方式二四、音频转码工具五、ffmpeg安装六、ffmpeg 使用说明七、ffmpeg命令八、查看音频格式ffprobe使用九、pcm文件音频时长计算十、转换为m4a格式&#xff08;AAC编码&#xff09; 一、创建应用 https://console.bce.baidu.com/a…

阿里云代理商:阿里云跨分部抵销前营收267.6亿元,跨分部抵销后营收207.57亿元,抵销后营收环比增长达17.37%。

阿里云代理商聚搜云专业服务于阿里云ECS服务器采购、阿里云Ddos采购、阿里云waf采购、对象存储OSS、阿里云企业邮箱采购、阿里云国际站代理商、阿里云国际站充值、云安全中心&#xff08;态势感知&#xff09;、阿里云高可用云数据库RDS、web应用云waf防火墙、阿里云vpc企业网、…

云GIS架构的研究与实践

云GIS架构的研究与实践 摘要1.引言2.云计算&#xff08;Cloud Computing&#xff09;3.云GIS4. 云GIS在“多规合一”平台中的实践4.1. 实践思路4.2. 相关产品选择4.3. 私有云环境建设4.4. 云GIS环境建设4.4.1. 镜像库4.4.2. 配置规则4.4.3. 生产站点4.4.4. 部署要点 5.总结参考…

华为云Modelarts

目录 一、什么是ModelArts 二、ModelArts特点 三、ModelArts开发流程 1、进入控制台 2、创建桶 3、自动学习 总结 一、什么是ModelArts ModelArts 是面向开发者的一站式 AI 开发平台&#xff0c;为机器学习与深度学习提供海量数据预处理及交互式智能标注、大规模分布式训…

云原生安全介绍

1 云原生介绍 不同组织对云原生有不同的解释&#xff1a; 云原生概念最早出现于2010年&#xff0c;Paul Fremantle的一篇博客中提及一种架构&#xff0c;其中包括&#xff1a;分布式、松散、自服务、持续部署与测试。 2015年Pivotal公司的Matt Stine在《迁移至云原生应用架构…

电子邮箱怎么填写格式,手机邮箱格式怎么填写?

电子邮箱作为主流的沟通工具之一&#xff0c;已经是人人必备的了&#xff0c;就像手机号码一样&#xff0c;每个人的邮箱地址都是不一样的&#xff0c;而且也存在着热门的“靓号”。一个好的邮箱地址不仅能吸引他人的眼球&#xff0c;让收信人更愿意阅读&#xff0c;还能便于自…

element自定义邮箱和手机号校验规则

<el-form:model"addUserForm"ref"addUserFormRef":rules"addUserFormRules"label-width"100px"><el-form-item label"邮箱" prop"email"><el-input v-model"addUserForm.email"><…

android qq 邮箱格式,QQ邮箱格式怎么写

QQ邮箱格式怎么写 QQ邮箱现在最多可以拥有四个不同的邮箱格式&#xff0c;但是别人不管给你哪个账号发邮件&#xff0c;你都可以在同一个邮箱收到邮件。所以可以在不同场合&#xff0c;可以给对方不同的邮箱账号。那么QQ邮箱格式怎么写呢&#xff1f;怎么在合适的场合给别人一个…

163邮箱怎么申请?手机号怎么申请注册邮箱?

如果你还没有邮箱&#xff0c;直接用手机号注册163邮箱&#xff0c;163.net是一款TOM的VIP邮箱&#xff0c;跟普通邮箱的区别是邮箱容量可以无限放大&#xff0c;来往的邮件信息能长期存储&#xff0c;国际邮件能快速收到和发出。 怎么申请邮箱&#xff1f;163邮箱申请的好处 …

手机号邮箱怎么注册?邮箱登陆163登录入口

公司一直都是用邮箱沟通交流的&#xff0c;新入职同事问我怎么注册邮箱&#xff0c;了解到他的岗位需要经常外出&#xff0c;就告诉他可以用手机邮箱&#xff0c;于是&#xff0c;告诉他注册TOMVIP邮箱就可以。同时简要整理了手机邮箱怎么注册&#xff1f;注册后的邮箱登陆流程…

Java实现利用正则表达式校验手机号码,邮箱,电话号码

需求&#xff1a; 校验手机号码&#xff0c;邮箱&#xff0c;电话号码 实现代码&#xff1a; package apilambda.d6_regex;import java.util.Scanner;public class RegexTest2 {public static void main(String[] args) {//需求&#xff1a;校验手机号码&#xff0c;邮箱&…

手机号电子邮箱怎么填写?

邮箱的格式是由账号名称域名组成&#xff0c;而账号名称可以是人名、公司名称以及手机号&#xff0c;这些都可以在注册邮箱时自行设定&#xff0c;TOM企业邮箱开通手机号邮箱仅需两分钟。 手机号电子邮箱 企邮开通好后会先拿到一个管理员账号&#xff0c;可以通过该账号进行开…

短视频解析去水印在线 伪原创视频如何搬运

短视频解析去水印在线 伪原创视频如何搬运 原创号1万的播放量是12元左右&#xff0c;具体的单价要根据账号权重所定。,您还可以使用更多视频网站进行分析。,相比之下&#xff0c;用户更喜欢空对地以接近群众。,2音频图片合并首先去网上选择一段合适的音乐素材&#x…

Vue中使用Video标签播放 <解析后的短视频>去水印视频无响应

&#x1f4e3;文章目录 问题&#xff1a;情景复现:链接在Video标签打不开链接浏览器正常打开出现的原理 解决方式前端解决全局添加标签Vue单页面添加标签完美解决: 问题&#xff1a; 发送Ajax请求,请求后端接口解析抖音无水印视频并且展示在页面中&#xff0c;后端已经可以把解…