设备搜索相关协议使用

一、实现原理

  1. 首先,Client -> Gateway : 发送 UDP 广播包(含厂商自定义协议)这一步表示客户端开始向网络中发送一个包含厂商自定义协议的 UDP 广播包,目的是寻找本厂商的设备(网关)。客户端此时处于活动状态activate Client,而网关开始等待接收广播包,也进入活动状态activate Gateway
  2. 当网关接收到符合厂商协议的广播包后,Gateway -> Client : 回复 UDP 包(若符合厂商协议),向客户端回复一个 UDP 包,告知自己的存在。之后客户端和网关的 UDP 交互暂时结束,状态变为不活动deactivate Clientdeactivate Gateway
  3. 接着,网关会在自己这一端Gateway -> Gateway : 建立 TCP 服务器,等待客户端的连接。当客户端准备好后,Client -> Gateway : 发起 TCP 连接,向网关发起 TCP 连接请求。网关收到请求后,Gateway -> Client : 接受 TCP 连接,接受客户端的连接,此时两者建立起了 TCP 长连接。
  4. 建立连接后,客户端可以向网关Client -> Gateway : 问询信息,询问所需的信息,网关收到请求后Gateway -> Client : 返回信息,将相应的信息返回给客户端。
  5. 然后,客户端可能需要向网关发送点表文件,即Client -> Gateway : 发送点表文件,网关接收文件后Gateway -> Client : 接收点表文件确认,向客户端返回接收确认信息。
  6. 最后,为了保持连接的活跃性,客户端会定期向网关Client -> Gateway : 发送心跳包,网关收到后Gateway -> Client : 回应心跳包,表示连接仍然正常。

二、相关协议

1、设备搜索协议

客户端—>搜索响应进程

客户端发送自定义标识,比如厂家名称字符串,这里自行协定

搜索响应进程—>客户端

设备收到协定的字符串校验成功后,回复"yes"

2、交互协议

这里的通信是基于TCP完成的,格式是json。通过type字段来标定事务类型,type取值如下(可以继续扩展):

1:获取运行时必要的参数信息
2:点表下发
3:心跳包

3、运行状态请求协议

客户端运行后首先下发此请求包,确认设备端是否已经有了点表配置文件。如果没有,那么下一步就是给设备下发点表文件;如果设备已经有了(下发过),那么需要获取设备的某些配置信息,以便QT后续运行使用。 ** 客户端--->搜索响应进程**
{"type": 1
}

** 搜索响应进程--->客户端** 设备出厂时候肯定是没有点表信息的,所以需要客户端下发,那么此时给客户端的回复up_config字段为true,后续的data无需添加。如果设备判断已经有这个点表了,那么up_config字段应该为false,并且把QT所需要的一些配置发回,添加上data字段(设备中的配置永远是最新的)。
{"type": 1,"result": 0, //成功返回0,失败返回1"up_config": false, //是否需要下发点表 true:需要下发,false:不需要下发"data": {  //配置信息,当up_config为true时不需要加data字段,false需增加此字段"mqtt_config":{"mqtt_addr": "192.168.1.2",  //mqtt服务器的地址"mqtt_port": 1883  //mqtt的端口      },"video_config":{"video_addr":"192.168.8.8", //监控服务的地址"video_port":8888 //监控服务的端口      },"update_config":{"type":1, //上报模式 0-不上报,客户端主动采集;1-变化上报,即连续2次值不相等;2-周期上报"period": 5 //上报周期时间,单位秒,仅在type=2时需要增加},xxx  //按需可继续添加}
}

4、配置下发协议
如果设备需要客户端下发点表配置文件(设备首次运行),那么在上述协议交互后,客户端会进行配置下发请求。
客户端文件下发是一个很常规的操作,比如配置文件、后期的升级文件都可以用这种方式进行。这里我们模仿下真正的FTP协议的流程来完成文件传输,参考下面的思想。
FTP端口号20和21的区别是21端口用于连接,20端口用于传输数据。进行FTP文件传输时,客户端首先连接到FTP服务器的21端口,进行用户的认证。认证成功后,要传输文件时,服务器会专门开一个新的端口20,来进行传输数据文件。所以传输文件时,实际上是一路新的链接,传输成功后,客户端会主动断开这一路链接。
所以,我们也模仿这个流程,可以定义8000端口专门用来做命令的控制,而8001这个端口来做文件的传输。
提示:一个进程是可以同时建立多个TCP链路的,所以这个流程我们可以保持8000端口的链路常开,当收到文件传输命令后,再开启一路8001socket端口监听,等待文件传输完成后,再关闭掉这路socket。FTP的思想就是文件传输链路随用随开,用完即关。FTP也常用在固件升级等场景中,下发的文件可能会很大。
两个端口的处理你可以用多线程、多进程、IO多路复用,这些思路都可以,只要能实现就行,下面给出一个select和线程结合的例子,仅作为参考。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>#define N 64typedef struct sockaddr SA;//这个例子里模拟了两个端口的响应,第一个端口用8888,第二个用6666
//模型用的select配合着线程实现的,仅作为参考void *new_sock(void *arg)
{printf("will recv new connect\n");int sockfd, clientfd;char buf[N];int addrlen = sizeof(struct sockaddr);struct sockaddr_in addr, clientaddr;int nbytes;// 1创建一个套接字--socketsockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){perror("socket err");exit(-1);}// 2定义套接字地址--sockaddr_inbzero(&addr, addrlen);addr.sin_family = AF_INET;addr.sin_addr.s_addr = INADDR_ANY;addr.sin_port = htons(6666);  //新的连接用6666端口// 3绑定套接字--bindif (bind(sockfd, (struct sockaddr *)&addr, addrlen) < 0){perror("bind err");exit(-1);}// 4启动监听--listenif (listen(sockfd, 5) < 0){perror("listen err");exit(-1);}// 5接收连接--acceptclientfd = accept(sockfd, (struct sockaddr *)&clientaddr, &addrlen);if (clientfd < 0){perror("accept err");exit(-1);}printf("recv new client\n");// 6收发数据--recv/sendwhile (1) {nbytes = recv(clientfd, buf, N, 0);if(nbytes < 0) {perror("recv err");exit(-1);} else if (nbytes > 0) {printf("recv %s-%d data = %s\n", inet_ntoa(clientaddr.sin_addr), \ntohs(clientaddr.sin_port), buf);} else {printf("peer exit\n");break;}}}int main(int argc, char *argv[])
{// 1.定义变量int i, listenfd, connfd, maxfd, n;char buf[N];fd_set rdfs, rdtmp;struct sockaddr_in myaddr;if (argc < 3){puts("server <addr> <port>");return -1;}// 2.创建套接字并监听if ((listenfd = socket(PF_INET, SOCK_STREAM, 0)) < 0){perror("socket err");exit(-1);}bzero(&myaddr, sizeof(myaddr));myaddr.sin_family = AF_INET;myaddr.sin_addr.s_addr = INADDR_ANY;myaddr.sin_port = htons(8888);  //第一个链接用8888if (bind(listenfd, (SA *)&myaddr, sizeof(myaddr)) < 0){perror("fail to bind");exit(-1);}listen(listenfd, 5);// 3.更新最大文件描述符,并设置关注集maxfd = listenfd;FD_ZERO(&rdfs);          // 清空关注列表FD_SET(listenfd, &rdfs); // 将fd放入关注列表中while (1){rdtmp = rdfs;// 5.调用select进行监听if (select(maxfd + 1, &rdtmp, NULL, NULL, NULL) < 0){perror("select err");exit(-1);}// 遍历集合,如果服务器句柄有数据,那么代表有连接进来,把它加入描述符集并更新maxfd// 否则代表客户端句柄有数据,那么接收数据,如果对端退出,那么把它从描述符集清除for (i = 0; i < maxfd + 1; i++){if (FD_ISSET(i, &rdtmp)){if (i == listenfd){ // 表示有新连接进来connfd = accept(listenfd, NULL, NULL);FD_SET(connfd, &rdfs);if (connfd > maxfd){maxfd = connfd;}}else{ // 客户端有数据bzero(buf, N);n = recv(i, buf, N, 0);if (n > 0){printf("recv from %d--%s\n", i, buf); // 记得加\n冲刷缓冲区if (strncmp(buf, "new", 3) == 0){// 新建一个新的服务器,这里如果还想保证8888的端口客户端正常响应,必须开线程,否则会阻塞到新的操作中pthread_t tid;pthread_create(&tid, NULL, new_sock, NULL);}}else if (n == 0){FD_CLR(i, &rdfs);close(i);}else{}}}}}return 0;
}

客户端—>搜索响应进程

{"type": 2, "data": {"flag":"start",  // start:准备发送 data:文件数据  stop:发送完毕"file_name":"node.json",  //点表文件名,flag为start需要填写"file_len":560 //点表文件长度,flag为start需要填写}
}

搜索响应进程—>客户端
只有当flag为"start"或者"stop"时,需要回复;

{"type": 2"data": {"flag":"start"  // start:准备接收  stop:接收完成}
}

说明:当客户端收到start请求帧的回复后,就会连接网关的8001端口,进行文件的传输。网关需要根据请求帧的信息来完成文件的命名。当文件传输完成后,客户端会主动断开8001的TCP链接,并通过控制链路发送stop帧告知已经发送完成。设备收到stop帧后关闭文件,然后回复stop帧完成点表的下发请求。

5、心跳协议

心跳机制是用来检测和设备的连接的,如果连接正常,那么客户端会回复。
心跳包疑惑解释
客户端—>搜索响应进程

{"type": 3
}

搜索响应进程—>客户端

{  
"type": 3,"result": 0, //无需回复任何东西,回复即代表活着
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/2650.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

TMDOG的Gin学习笔记_01——初识Gin框架

TMDOG的Gin学习笔记_01——初识Gin框架 博客地址&#xff1a;[TMDOG的博客](https://blog.tmdog114514.icu) 作者自述&#xff1a; 停更太久了&#xff0c;是因为开学了课太多了&#xff0c;并且我一直在准备上篇文章的内容正在coding&#xff0c;就先搁置了更新博客QAQ&…

H7-TOOL的CAN/CANFD助手增加帧发送成功标识支持, 继续加强完善功能细节

2.27版本固件正式携带此功能&#xff0c;包括之前做的负载率检测和错误信息展示也将集成到这个版本固件中。 对于接收&#xff0c;我们可以直接看到效果&#xff0c;而发送不行&#xff0c;所以打算在发送的地方展示下发送成功标识。CAN发送不像串口&#xff0c;需要等待应答后…

Pr 视频效果:超级键

视频效果/键控/超级键 Keying/Ultra Key 超级键 Ultra Key效果是 Premiere Pro 中功能强大的抠像工具&#xff0c;主要用于绿幕/蓝幕抠像。通过选择要抠除的颜色&#xff08;通常是绿幕或蓝幕的颜色&#xff09;&#xff0c;即可以将该颜色的像素设为透明&#xff0c;实现主体与…

善用Git LFS来降低模型文件对磁盘的占用

将讲一个实际的例子&#xff1a;对于模型文件&#xff0c;动辄就是好几个G&#xff0c;而有的仓库更是高达几十G&#xff0c;拉一个仓库到本地&#xff0c;稍不注意直接磁盘拉满都有可能。 比如&#xff1a;meta-llama-3.1-8b-instruct&#xff0c;拉到本地后发现居然占用了60G…

「树链剖分」学习笔记

一、引入 “在一棵树上进行路径的修改、求极值、求和”乍一看只要线段树就能轻松解决&#xff0c;实际上&#xff0c;仅凭线段树是不能搞定它的。我们需要用到一种貌似高级的复杂算法——「树链剖分」。 树链剖分&#xff08;简称树剖&#xff09;&#xff0c;顾名思义&#xf…

Golang--数组、切片、映射

1、数组 1.1 数组类型 var 数组名 [数组大小]数据类型 package main import "fmt"func main(){//1、定义一个数组var arr1 [5]intarr1[0] 100arr1[1] 200fmt.Println(arr1) //[100 200 0 0 0] } 1.2 数组的初始化方式 package main import "fmt" func …

结构体对齐,位段

大家好&#xff0c;今天来给大家分享一些结构体的知识&#xff0c;结构体是我们学习数据结构的基础&#xff0c;只有把它了解清楚才能让我们学习数据结构是得心应手&#xff0c;现在让我们来看看它的一些内容吧。 1.结构体的定义和调用我们就跳过吧 大家如果还不熟悉的话可以去…

ElementUI中el-table双击单元格显示输入框

效果图 实现 <el-table:data"formData.products"row-key"id":show-header"true"style"width: 100%; margin-top: 16px"class"zq-table-theme-info"bordercell-dblclick"handleDbClick"> <el-table-col…

Python OpenCV 图像改变

更改图像数据 通过 改像素点 或者 切片的区域 import cv2 import numpy as np img cv2.imread("image.jpg") print(img[3,5]) # 显示某位置(行3列5)的像素值( 如 [53 34 29] 它是有三通道 B G R 组成) img[3,5] (0,0,255) # 更改该位置的像素…

学习虚幻C++开发日志——定时器

官方文档&#xff1a;虚幻引擎中的Gameplay定时器 | 虚幻引擎 5.5 文档 | Epic Developer Community | Epic Developer Community 定时器 安排在经过一定延迟或一段时间结束后要执行的操作。例如&#xff0c;您可能希望玩家在获取某个能力提升道具后变得无懈可击&#xff0c;…

网络安全设备Bypass功能介绍及分析

网络安全平台厂商往往需要用到一项比较特殊的技术&#xff0c;那就是Bypass&#xff0c;那么到底什么是Bypass呢&#xff0c;Bypass设备又是如何来实现的&#xff1f;下面我就对Bypass技术做一下简单的介绍和说明。 一、 什么是Bypass。 大家知道&#xff0c;网络安全设备一般…

如何更改Android studio的项目存储路径

如果你希望永久更改Android Studio的默认项目保存路径&#xff0c;可以通过以下步骤进行设置&#xff1a; 打开Android Studio&#xff0c;选择“File”菜单下的“Settings”&#xff08;Windows&#xff09;或“Preferences”&#xff08;Mac&#xff09;。在设置窗口中&…

ESP8266 自定义固件烧录-mqtt透传固件

esp8266 mqtt固件配网及使用说明_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV196421G7Xc/?spm_id_from333.999.0.0一、固件介绍 固件为自定义开发的一个适配物联网项目的开源固件&#xff0c;支持网页配网、支持网页mqtt服务器配置、支持主题设置。 方便、快捷、稳…

二十三、Mysql8.0高可用集群架构实战

文章目录 一、MySQL InnoDB Cluster1、基本概述2、集群架构3、搭建一主两从InnoDB集群3.1、 安装3个数据库实例3.2、安装mysqlrouter和安装mysqlshell3.2.1、安装mysql-router3.2.2、安装mysql-shell 3.3、InnoDB Cluster 初始化3.1 参数及权限配置预需求检测3.2 初始化InnoDB …

[OS] mmap() 函数的参数及其作用

参数说明&#xff1a; addr&#xff1a;映射区域的起始地址。如果设置为 0&#xff0c;则由内核自动选择页对齐的地址。length&#xff1a;需要映射的字节数&#xff0c;决定映射的区域大小。prot&#xff1a;映射区域的内存保护属性&#xff0c;如只读、可读写等。这个属性不…

meta-learning based FD论文阅读笔记

[1]Semi-Supervised Temporal Meta-Learning Framework for Wind Turbine Bearing Fault Diagnosis Under Limited Annotation Data 问题背景 the fault data are so scarce that it is time-consuming to acquire a well behaved deep learning modelmuch unlabeled data ca…

web渗透——小白入狱

目录 理论知识总结一、Web渗透核心知识点二、Web渗透实操案例三、Web渗透学习建议实操案例一、信息收集实操步骤&#xff1a; 二、SQL注入实操步骤&#xff1a; 三、跨站脚本攻击&#xff08;XSS&#xff09;实操步骤&#xff1a; 四、CSRF攻击实操步骤&#xff1a; 五、本地文…

一个完整的产品级物联网系统在农业领域的应用,通过传感器、通信、云计算和控制设备的协同工作,实现了智能化的农业灌溉管理

以下为您详细介绍一个智能农业灌溉系统作为产品级的物联网实际案例&#xff1a; **一、项目背景** 随着农业现代化的发展&#xff0c;精准灌溉对于提高农作物产量、节约水资源具有重要意义。传统的灌溉方式往往依赖人工经验&#xff0c;效率低下且浪费水资源。因此&#xff0c…

JeecgBoot入门

最近在了解低代码平台&#xff0c;其中关注到gitee上开源项目JeecgBoot&#xff0c;JeecgBoot官方也有比较完整的入门教学文档&#xff0c;这里我们将耕者官方教程学习&#xff0c;并将其记录下来。 一、项目简介 JeecgBoot 是一款基于代码生成器的低代码开发平台拥有零代码能力…

qt QEvent详解

1、概述 QEvent是Qt框架中事件机制的基础类。在Qt中&#xff0c;事件是由底层窗口系统&#xff08;如Windows、Linux的X11、macOS的Cocoa等&#xff09;生成的&#xff0c;Qt的主事件循环&#xff08;QCoreApplication::exec()&#xff09;负责从事件队列中获取这些事件&#…