python实现FINS协议的UDP服务端

news/2025/2/14 2:54:20/

python实现FINS协议的UDP服务端是一件稍微麻烦点的事情。它不像modbusTCP那样,可以使用现成的pymodbus模块去实现。但是,我们可以根据协议帧进行组包,自己去实现帧的格式,而这一切可以基于socket模块。本文基于原先 FINS协议的TCP服务端的文章进行修改。

一、FINS TCP与FINS UDP

1、FINS_UDP与FINS_TCP有什么不同

FINS(Factory Interface Network Service)是欧姆龙(Omron)PLC(可编程逻辑控制器)的通信协议。FINS支持两种主要的传输方式:FINS over TCP(FINS_TCP)和FINS over UDP(FINS_UDP)。

下面是它们之间的主要区别:

(1)传输层协议:

FINS_TCP: 使用TCP(Transmission Control Protocol)作为传输层协议。TCP是面向连接的、可靠的协议,确保数据的可靠性和顺序传输。

FINS_UDP: 使用UDP(User Datagram Protocol)作为传输层协议。UDP是面向无连接的协议,它不保证数据的可靠性和顺序传输,但通常具有更低的延迟。

(2)连接方式:

FINS_TCP: 建立连接后进行通信,类似于常见的TCP通信方式。

FINS_UDP: 无连接,每个数据包独立发送,适用于对实时性要求较高的应用场景。

(3)可靠性和顺序性:

FINS_TCP: 提供TCP的可靠性和顺序性,适用于对数据完整性和传输顺序有要求的应用。

FINS_UDP: 不提供可靠性和顺序性的保证,适用于对实时性要求较高,可以容忍一些数据丢失的场景。

(4)用途:

FINS_TCP: 适用于对数据完整性和传输顺序要求较高的应用,例如需要确保每个数据包都被正确接收的场景。

FINS_UDP: 适用于实时性要求较高,可以容忍一些数据丢失的应用,例如对于实时控制要求较高的系统。

选择使用哪种方式取决于具体的应用场景和对通信特性的要求。

2、FINS_UDP与FINS_TCP的协议包有什么不同

(1)握手包

FINS_TCP有握手包,而FINS_UDP没有握手包。

(2)请求头

FINS_TCP的请求头是FINS,而FINS_UDP没有请求头。

(3)其他部分

一致。相关文档请查阅我之前写的“python实现FINS协议的TCP服务端(篇一)”等文章,现对比如下:

FINS_TCP

46 49 4E 53 00 00 00 1A 00 00 00 02 00 00 00 00 80 00 02 00 01 00 00 01 00 3D 01 01 82 00 64 00 00 01

FINS_UDP

                                                                                 80 00 02 00 FF 00 00 05 00 64 01 01 82 00 64 00 00 01

二、程序实现

1、构建响应帧

def recognition_frame(req_bytes_frame, Trigger):get_frame = req_bytes_frame.hex().upper()print("设备请求:", get_frame)SRC_value = get_frame[22:24]  # 判断读写,01为读,02为写Area_value = get_frame[24:26]  # 判断寄存器区域,82为保持寄存器# print(SRC_value)# print(Area_value)if SRC_value == "01":if Area_value == "82":response_1 = "00000000000000000000010100000001"  # Trigger位为Trueresponse_0 = "00000000000000000000010100000000"  # Trigger位为Falseif Trigger == True:return bytes().fromhex(response_1)else:return bytes().fromhex(response_0)else:raise ValueError("Area_value is error!")elif SRC_value == "02":if Area_value == "82":print("***************************************")# 写保持寄存器的响应print("扫码器写入的结果数据:", bytes().fromhex(get_frame))response = "0000000000000000000001020000"return bytes().fromhex(response)else:raise ValueError("Area_value is error!")else:raise ValueError("SRC_value is error!")

这个函数是针对读取或写入保持寄存器的请求,以下是对函数的解释:

(1)输入参数:

req_bytes_frame: 一个字节序列,表示设备请求的原始帧。Trigger: 一个布尔值,似乎用于确定设备是否处于触发状态。

(2)函数操作:

将输入的字节序列转换为十六进制表示,并转换为大写形式。从帧中提取 SRC(源)和 Area(寄存器区域)的值。

根据 SRC 和 Area 的值执行相应的逻辑:

如果 SRC 是 "01",表示读取请求,继续判断 Area 是否为 "82"(保持寄存器)。

如果不是 "82",抛出 ValueError 异常,表示 Area 值错误。

如果 SRC 是 "02",表示写入请求,同样判断 Area 是否为 "82"。

如果是,打印扫码器写入的结果数据,构建写保持寄存器的响应帧。如果不是 "82",同样抛出 ValueError 异常。

如果 SRC 不是 "01" 或 "02",抛出 ValueError 异常,表示 SRC 值错误。

如果是,根据 Trigger 的值构建响应帧,其中 Trigger 为 True 时触发位为 1,否则为 0。

(3)返回值:

如果是读取请求,返回构建的响应帧(True 触发位或 False 触发位)。

如果是写入请求,返回构建的写保持寄存器的响应帧。

(4)异常处理:

如果 Area 值不是 "82",或者 SRC 值不是 "01" 或 "02",都会抛出 ValueError 异常,提示相应的错误信息。

总体来说,该函数是为了处理设备的读取和写入请求,并根据请求类型和条件构建相应的响应帧。

2、服务器实现

if __name__ == "__main__":DM_start = 1000# 创建FINS服务端# 创建一个TCP/IP套接字server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)# 绑定套接字到特定地址和端口server_address = ('192.168.1.188', 9600)  # 服务器地址和端口server_socket.bind(server_address)try:num = 0  # 触发标志Trigger_rec = 0  # Trigger置为True时,对应变为1,表示触发一次response = "" # 响应while True:# 接收客户端请求request, client_address = server_socket.recvfrom(1024)if request:# 如果收到的不是请求头if "800002" in request.hex():# print(request.hex()[22:24])# 实现扫码触发if request.hex()[22:24] == "01":  # 判断读写,01为读触发指令,02为写触发结果if Trigger_rec != 2:Trigger_rec += 1if Trigger_rec == 1:response = recognition_frame(request, Trigger=False)  # 先清空触发信号server_socket.sendto(response, client_address)elif Trigger_rec == 2:  # 复位Trigger信号response = recognition_frame(request, Trigger=True)  # 再置位触发信号server_socket.sendto(response, client_address)# 实现结果接收elif request.hex()[22:24] == "02":print(request.hex())# print("---------------", int(request.hex()[26:30], 16))if int(request.hex()[26:30], 16) == DM_start + 4:if any(c != '0' for c in request.hex()[36:]):  # 不全为0print("扫码结果:", request.hex()[36:])num += 1Trigger_rec = 0else:response = recognition_frame(request, Trigger=True)server_socket.sendto(response, client_address)print("还没有收到结果,继续等待扫码结果!")else:response = recognition_frame(request, Trigger=True)server_socket.sendto(response, client_address)# 处理其他请求else:response = recognition_frame(request, Trigger=True)server_socket.sendto(response, client_address)print("服务响应:", response.hex())  # 可以响应为空if num == 1:assert bytes().fromhex(request.hex()[36:]).decode() != "NG", "实际扫码结果为:{},不符合预期".format(bytes().fromhex(request.hex()[36:]).decode())breakrequest = Falsefinally:# 清理连接server_socket.close()

这段代码是一个服务端程序,是套接字UDP服务端。让我们分析主要的部分:

(1)服务端设置:

创建一个UDP套接字(socket.AF_INET, socket.SOCK_DGRAM)用于与客户端通信。绑定套接字到特定的地址和端口(('192.168.1.188', 9600))。

(2)主循环:

在一个无限循环中,服务端等待从客户端接收请求。对于收到的请求,根据请求的内容进行不同的处理。

(3)请求处理:

判断请求是否包含特定的头部标识 "800002"。如果是读触发指令("01"),则处理触发逻辑。如果是写触发结果指令("02"),则处理扫码结果。如果是其他请求,统一进行处理。

(4)触发逻辑:

根据触发标志 (Trigger_rec) 的状态,对触发指令进行相应的处理。首先清空触发信号,然后再置位触发信号。

(5)扫码结果处理:

对于写触发结果指令,检查是否收到了预期的扫码结果。如果扫码结果不全为0,则认为收到有效的扫码结果,增加计数。如果结果为0,继续等待扫码结果。

(6)响应处理:

根据处理后的结果,调用 recognition_frame 函数构建响应帧。将响应发送给客户端。

(7)断言和终止条件:

当计数 num 达到1时,使用断言检查扫码结果是否符合预期,并终止程序。

(8)清理:

finally 块中关闭套接字,确保程序退出时资源被释放。

总体来说,这个服务端程序用于处理来自客户端的请求,其中包括了特定的触发指令和扫码结果指令。在处理这些指令时,它通过 recognition_frame 函数构建响应,并对结果进行相应的处理。


http://www.ppmy.cn/news/1257959.html

相关文章

「吞噬星空」布罗占地球奖1000亿,罗峰洪雷神诱敌深入,狩猎开始

Hello,小伙伴们,我是拾荒君。 国漫《吞噬星空》第96集更新,和许多激动的漫迷一样,一更新拾荒君就去观看。这一集中,罗峰在白兰星司长的介绍下,决定购买仓库基地的永久产权和两栋九层城堡。他使用黑龙币支付了272万&am…

计算机网络:可靠数据传输(rdt)、流水协议、窗口滑动协议

文章目录 前言一、Rdt1.Rdt1.02.Rdt2.03.Rdt2.14.Rdt2.25.Rdt3.0 二、流水线协议1.滑动窗口(slide window)协议发送窗口接收窗口正常情况下的2个窗口互动异常情况下GBN的2个窗口互动异常情况下SR的2窗口互动GBN协议和SR协议的异同 2.小结 总结 前言 Rdt…

自定义一个简单的JDBC连接池实现方法(附代码演示)

Hi i,m JinXiang ⭐ 前言 ⭐ 本篇文章主要介绍自定义一个简单的JDBC连接池实现方法以及部分理论知识 🍉欢迎点赞 👍 收藏 ⭐留言评论 📝私信必回哟😁 🍉博主收将持续更新学习记录获,友友们有任何问题可以在…

活动目录是什么?

企业在进行数字化转型时,也会面临日益增长的网络用户和复杂的身份管理需求。为了高效地管理用户身份、控制访问权限以及保护企业的数据安全,许多企业选择使用微软的Active Directory,即微软活动目录,来作为网络身份管理系统。 1、…

linux 安装 Apache 服务 并部署网站

作者简介:一名云计算网络运维人员、每天分享网络与运维的技术与干货。 公众号:网络豆云计算学堂 座右铭:低头赶路,敬事如仪 个人主页: 网络豆的主页​​​​​ 写在前面 哈喽大家我是网络豆,本章将会…

git的基本命令操作超详细解析教程

Git基础教学 1、初始化配置2、初始化仓库3、工作区域和文件状态4、添加和提交文件5、git reset 回退版本6、git diff查看差异7、删除文件git rm8、.gitignore10、分支基础应用1、本地文件提交到远程仓库 Git:一个开源的分布式版本控制系统,它可以在本地和…

Scrum敏捷开发流程及支撑工具

Scrum是一种敏捷开发框架,用于管理复杂的项目。以下这些步骤构成了Scrum敏捷开发流程的核心。通过不断迭代、灵活应对变化和持续反馈,Scrum框架帮助团队快速交付高质量的产品。 以下是Scrum敏捷开发流程的基本步骤: 产品Backlog创建&#xf…

三、使用CRT连接三台虚拟机

目录 1、建立连接 2、参数配置 3、设置主题,颜色和仿真 1、建立连接