UDP协议在物联网中的实战

一、UDP协议介绍

UDP(User Datagram Protocol, 用户数据报协议),无连接的传输层协议,提供面向事务的简单不可靠信息传输服务。强调传输性能而不是传输完整性,多用于视频和多媒体应用。

2.1 报文格式

在这里插入图片描述

2.2 协议特点

  • 无连接
  • 不可靠传输:消息尽力传播,但不关注是否传输过去
  • 面向数据报:以数据报为传输的基本单位,不拆分、不合并、原样发送
  • 全双工:一条路径双向通信,既能读,也能写
  • 大小受限:UDP协议首部有2个字节,16位的长度内容,限制了UDP传输数据最大长度为64K(含UDP首部)
  • 缓冲区:UDP只有接收缓冲区,没有发送缓冲区

二、物联网中实战

不同物联网平台对协议中所承载的业务内容均有自己的规范,但原理基本一致,本文基于中国电信AIoT物联网平台进行实战。

2.1 在物联网平台创建产品设备

具体操作流程可见平台操作手册

重点关注:

  • 创建产品时,通信协议选择UDP
  • 创建产品时,“是否透传”,选择透传或者物模型,将对应不同的上下行报文格式。透传:平台对报文不进行解析,将报文透传给应用或终端;物模型:按照在平台定义的服务与属性,对上下行报文进行解析。(https://img-blog.csdnimg.cn/direct/d73abe3f1bf04acbada68b35c964bd3f.jpeg)
    在这里插入图片描述

2.2 交互流程

设备登录

在这里插入图片描述

  1. 用户在通用组件服务添加设备,填写设备编号。通用组件服务生成device ID和特征串。device ID由产品ID和设备编号拼接生成。设备初始状态为:已注册。

  2. 设备携带deviceId、password(平台生成的特征串)登录到平台

  3. 平台对设备进行认证,并将认证结果返回给设备。认证成功后,设备状态为:已激活、在线。

心跳保活
在这里插入图片描述

  1. 平台默认心跳周期为5分钟,心跳超时之前,设备需要发送心跳报文到平台用于会话的延长。超时而没有发送心跳报文的,平台将删除会话。

数据上报
在这里插入图片描述

  1. 设备以0x04消息类型上报数据,平台解析后会以0x84回复响应结果。

下行指令
在这里插入图片描述

设备登出
在这里插入图片描述
3. 设备登出需要发送登出请求,携带deviceId,平台收到请求后删除会话,并向设备发送登出响应。设备状态更新为:下线。

2.3 报文格式(下文转自官方手册)

消息格式

应用层数据报文以1个字节的类型字段作为分割,平台支持登录、心跳、上下行业务数据、登出等消息类型。消息携带的参数必须包含两个字节的参数长度。

UDP报文Payload包含三部分内容:

消息类型(1 BYTE)消息ID(2 BYTE)、消息内容(n BYTE)。

消息类型

消息ID

消息内容

 

定义8种消息类型:

消息类型

类型描述

0x01

登录请求

0x02

心跳

0x03

登出请求

0x04

上行数据

0x05

下行数据

0x81

登录响应

0x82

心跳响应

0x83

登出响应

0x84

上行数据响应

0x85

下行数据响应

 

登录消息

类型描述

消息类型

消息ID

消息内容格式

备注

登录请求

0x01

设备生成,2个字节

[deviceId_length (2字节)]+[deviceId]

+[password_length(2字节)]+[password]

+[version_length(2字节)]+[version]

deviceId由产品Id和设备编号拼接而成的字符串;version默认填写为1.0

登录响应

0x81

与请求报文一致。

结果码(1字节)

登录结果:

0 成功

1 未知错误

2 设备不存在

3 设备认证失败

心跳消息

类型描述

消息类型

消息ID

消息内容格式

备注

心跳请求

0x02

设备生成,2个字节

[deviceId_length (2字节)]+[deviceId]

终端与平台心跳周期暂定5分钟;

心跳响应

0x82

与请求报文一致。

结果码(1字节)

心跳结果:

0 成功

1 设备id错误或设备不在线


业务数据

透传

类型描述

消息类型

消息ID

消息内容格式

备注

上行数据

0x04

设备生成,2个字节

[deviceId_length (2字节)] +[deviceId]

+[data_length (2字节)] +[data]

data_length字段不可为0

上行数据响应

0x84

与请求报文一致。

结果码(1字节)

上报结果:

0 成功

1 设备id错误或设备不在线

下行数据

0x05

平台生成,2个字节(taskId)

[data_length (2字节)]

+[data]


下行数据响应

0x85

与请求报文一致。(taskId)

结果码(1字节)+[data_length (2字节)]

+[data]

指令执行结果码:

0 成功

1 失败

data_length字段可设置为0

 

非透传

类型描述

消息类型

消息ID

消息内容格式

备注

上行数据

0x04

设备生成,2个字节

[deviceId_length (2字节)] +[deviceId]

+[data_length (2字节)] +[serviceId (2字节)] +[params]

data_length为serviceId字段与 params字段的总长度

上行数据响应

0x84

与请求报文一致。

结果码(1字节)

上报结果:

0 成功

1 设备id错误或设备不在线

下行数据

0x05

平台生成,2个字节(taskId)

[data_length (2字节)]

+[serviceId (2字节)] +[params]

data_length为serviceId字段与 params字段的总长度

下行数据响应

0x85

与请求报文一致。(taskId)

结果码(1字节)+[data_length (2字节)]

+[serviceId (2字节)] +[params]

指令执行结果码:

0 成功

1 失败

data_length字段可设置为0

data_length为serviceId字段与 params字段的总长度


1. 上行数据

物模型如下:

服务类型

服务标识

服务ID

属性顺序

属性标识符

属性类型

属性长度

数据上报

up

1

1

seq

无符号整型

2




2

data1

定长字符串

5




3

data2

变长字符串

/


2. 下行数据

物模型如下:

服务类型

服务标识

服务ID

参数顺序

参数标识符

参数类型

参数长度

指令下发

dn

8001

1

cmd

定长字符串

5

指令下发响应

rsp

9001

1

time

定长字符串

5

2.4 代码

2.4.1 代码总体框架

每一次进行业务交互,主要是对client.sendto(payload, server_address)payload部分和client.recvfrom(1024)的内容进行编辑与解析。

import socket

# 创建UDP socket
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 服务器地址
# 获取服务端主机与端口,可在设备管理->产品->产品概况中查看,如果是域名,可在本地ping一下获得IP
host = "180.109.255.252"
# 设置端口与服务器端一致
port = 15683
server_address = (host, port)

# 发送消息
# client.sendto(payload, server_address)

# 接收回应
# response, server_address = client.recvfrom(1024)
# print(f"Received response: {response}")

# 关闭socket
client_socket.close()

2.4.1 UDP透传设备

2.4.1.1. 登录

1.登录报文

消息格式:[deviceId_length (2字节)]+[deviceId]+[password_length(2字节)]+[password]+[version_length(2字节)]+[version]

注:字符串转十六进制可用在线工具:https://www.sojson.com/hexadecimal.html,也可以直接使用python中的bytes(data, "utf-8").hex()方式。


deviceId:200020722

password:7Sfv-b_HDbLDyJ_K-0SkWqRGd-GE-b3rZp-upOr1kSU

version:1.0

登录请求编码为(16进制):

• 登录报文消息类型:0x01

• 消息Id:0x0001

• deviceId_length:0x0009

• deviceId:0x323030303230373232

• password_length:0x002b

• password:0x382D45654D57466134364D5952566C4149683557393967714E35395A5571565A34487653634C7A50456259

• version_length:0x0003

• version:0x312e30

登录请求的完整报文为:01 0001 0009 323030303230373232 002B 382D45654D57466134364D5952566C4149683557393967714E35395A5571565A34487653634C7A50456259 0003 312E30

2. 登录代码全貌

import socket
import binascii
# 创建UDP socket
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 服务器地址
# 获取服务端主机与端口,可在设备管理->产品->产品概况中查看,如果是域名,可在本地ping一下获得IP
host = "180.109.255.252"
# 设置端口与服务器端一致
port = 15683
server_address = (host, port)

# 发送消息
payload = "0100010009323030303230373232002B382D45654D57466134364D5952566C4149683557393967714E35395A5571565A34487653634C7A504562590003312E30"
client.sendto(binascii.unhexlify(payload), server_address)

# 接收回应

response = binascii.hexlify(client.recv(1024)).decode("utf-8")
print(f"Received response: {response}")

# 关闭socket
client.close()

根据平台定义的登录响应格式,TCP模拟器收到“050000”的报文,则登录成功,在物联网平台可查看设备状态也应该为在线。

2.4.1.2 数据上报

1.上报报文

消息格式:0x02 +数据长度(2字节) +业务数据

deviceId:200020722

1. 上行业务数据:"hello"

上行数据编码为(16进制):

• 上行数据消息类型:0x04

• 消息Id:0x0004

• deviceId_length:0x0009

• deviceId:0x323030303230373232

• data_length:0x0005

• data:0x68656c6c6f

上行数据的完整报文为:04 0004 0009 323030303230373232 0005 68656c6c6f

2. 上行代码全貌
根据业务规则,设备需先登录,才能进行数据上报。

import socket
import binascii
# 创建UDP socket
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 服务器地址
# 获取服务端主机与端口,可在设备管理->产品->产品概况中查看,如果是域名,可在本地ping一下获得IP
host = "180.109.255.252"
# 设置端口与服务器端一致
port = 15683
server_address = (host, port)

# 发送登录消息
payload = "0100010009323030303230373232002B382D45654D57466134364D5952566C4149683557393967714E35395A5571565A34487653634C7A504562590003312E30"
client.sendto(binascii.unhexlify(payload), server_address)

# 接收回应
response = binascii.hexlify(client.recv(1024)).decode("utf-8")
print(f"Received response: {response}")

# 发送上报消息
payload2 = "0400040009323030303230373232000568656c6c6f"
client.sendto(binascii.unhexlify(payload2), server_address)
# 接收回应
response2 = binascii.hexlify(client.recv(1024)).decode("utf-8")
print(f"Received response: {response2}")

# 关闭socket
client.close()

经过登录和上行报文的实战,有没有发现UDP协议在物联网领域中,实质是将业务数据封装在了UDP报文的data部分。data部分按照业务规则进行”拼接“即可。

相关推荐

  1. Wireshark联网应用

    2024-06-09 20:06:01       28 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-06-09 20:06:01       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-09 20:06:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-09 20:06:01       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-09 20:06:01       20 阅读

热门阅读

  1. 在 Linux 使用 cron 定时执行任务的注意事项

    2024-06-09 20:06:01       9 阅读
  2. Linux_第五章_实验案例:用户和文件权限管理

    2024-06-09 20:06:01       14 阅读
  3. Linux fallocate工具用于预分配或释放文件空间的块

    2024-06-09 20:06:01       12 阅读
  4. 新增菜品——后端SpringBoot

    2024-06-09 20:06:01       10 阅读
  5. python手动搭建transformer,并实现自回归推理

    2024-06-09 20:06:01       12 阅读
  6. 如何实现观察者模式和发布-订阅模式?

    2024-06-09 20:06:01       11 阅读
  7. 关于 Git 的几个使用技巧

    2024-06-09 20:06:01       9 阅读
  8. 速盾:网站重生之我开了高防cdn

    2024-06-09 20:06:01       12 阅读
  9. 贪心算法 之 股票 跳跃游戏1and2

    2024-06-09 20:06:01       9 阅读
  10. flink学习-处理函数

    2024-06-09 20:06:01       12 阅读