python实现MC协议(SLMP 3E帧)的TCP服务端(篇二)-CSDN博客

  • 阿里云国际版折扣https://www.yundadi.com

  • 阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

    python实现MC协议SLMP 3E帧的TCP服务端是一件稍微麻烦点的事情。它不像modbusTCP那样可以使用现成的pymodbus模块去实现。但是我们可以根据协议帧进行组包自己去实现帧的格式而这一切可以基于socket模块。本文为第二篇。

    二、读写保持寄存器的完整交互包

    # 客户端发送读 -》
    50 00 00 FF FF 03 00 0C 00 10 00 01 04 00 00 00 00 00 A8 05 00
    # 《- 服务端应答
    D0 00 00 FF FF 03 00 0C 00 00 00 73 00 00 00 00 00 00 00 00 00
    # 客户端发送写 -》
    50 00 00 FF FF 03 00 16 00 10 00 01 14 00 00 0A 00 00 A8 05 00 4E 47 00 00 00 00 00 00 00 00
    # 《- 服务端应答
    D0 00 00 FF FF 03 00 02 00 00 00

    1、分析交互包

    基于上述交互包我们查阅官方文档发现交互包使用的是二进制代码。那么二进制代码与ASCII代码有什么区别呢

    SLMPSeamless Message Protocol3E帧有两种表示方式二进制格式和ASCII格式。它们的区别在于数据的传输方式和呈现形式。

    1二进制格式

    在二进制格式中SLMP 3E帧中的各个字段如帧头、副帧头、命令码、数据等以二进制形式直接编码和传输。数据在网络中以原始的二进制位模式传输这种方式效率较高适用于网络传输。二进制格式通常用于实际的网络通信中数据以二进制流的形式在网络上传输。

    2ASCII格式

    在ASCII格式中SLMP 3E帧中的各个字段被转换成ASCII字符表示。数据以ASCII码的文本形式进行传输每个字节被转换为两个ASCII字符通常是十六进制表示。ASCII格式通常用于调试和人机界面中方便人们查看和理解数据。

    总的来说二进制格式适用于机器之间的网络通信而ASCII格式适用于人机交互和调试过程中的数据显示。选择哪种格式取决于具体的应用场景和需求。

    因此本文实现的是二进制格式如果你会实现二进制格式那么你也能实现ASCII格式。

    2、读写保持寄存器的请求处理

    1表头

    客户端的两个请求相同部分都为50 00 00 FF FF 03 00我们姑且称之为表头。

    2读/写长度协议帧的长度

    0C 00是固定长度读的时候报文都是这么长与16 00 根据实际长度变化表示后面数据的长度例如前者应该以00 0C来看长度表示后面有12个00那样的长度。

    3固定值

    10 00

    4读/写指令

    01 04 / 01 14

    5读/写寄存器地址

    00 00 00 00 00 A8 05 00 /  00 00 0A 00 00 A8 05 00其中写的0A 00代表从第10个保持寄存器05表示读写5个寄存器

    3、读写保持寄存器的响应处理

    1表头

    客户端的两个请求相同部分都为D0 00 00 FF FF 03 00我们姑且称之为表头。

    2长度协议帧的长度

    读0C 00根据实际长度变化写02 00 可以不变化。

    3固定值

    00 00

    4读/写响应

    响应实际读到的数据 / 无

    4、程序设计

    根据上述内容实现了一个定制MC服务器能够处理保持寄存器的读写请求给出正确的响应。

    import socket
    import struct
    
    # 创建一个TCP/IP套接字
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    # 绑定套接字到特定地址和端口
    server_address = ('192.168.1.188', 12345)  # 服务器地址和端口
    server_socket.bind(server_address)
    
    # 监听连接
    server_socket.listen(1)
    
    print('等待客户端连接...')
    connection, client_address = server_socket.accept()
    
    print('客户端已连接:', client_address)
    
    def request_verdict(req_bytes_frame):  # req_bytes_frame是字节数据b'\x02\x00\x08\x00\x00\x00\x00\x00\x10\x00\x01\x01\x02\x03\x04\x03'
        command = req_bytes_frame.hex()[22:26]  # 转成16进制字符串好数据处理
        if command in ["0104", "0401"]:  # 判断读写
            return False # 读
        elif command in ["0114", "1401"]:
            return True  # 写
        else:
            raise ValueError("读写指令错误")
    
    def write_response_frame(req_bytes_frame):
        response = "D00000FFFF030002000000"  # 写成功则返回这一串数据
        content = req_bytes_frame.hex()[42:]  # 看一下客户端想写的内容
        print("客户端想要写入的内容", bytes.fromhex(content).decode())
        return bytes().fromhex(response)
    
    def read_response_frame(req_bytes_frame, res_data):
        header = "D00000FFFF03000C000000"  # 读的响应头
        nums = req_bytes_frame.hex()[38:42]  # 获取客户端想要读的寄存器个数
        act_nums_hex = nums[2:] + nums[:2]  # 涉及大端序和小端序需要转一下
        act_nums = int(act_nums_hex, 16)  # 得到实际数量
        res_data_hex = ''.join([hex(ord(c))[2:].zfill(2) for c in res_data])  # 将要返回的数据转成16进制字符串
        response = header + res_data_hex + '0'*(act_nums*2*2-len(res_data_hex))  # 根据请求数量返回对应的内容
        return bytes().fromhex(response)
    
    try:
        while True:
            # 接收客户端请求
            request = connection.recv(1024)
            print("001:", request)
            if request:
                flag = request_verdict(request)
                if flag:  # 响应写
                    response = write_response_frame(request)
                    print("002:",response)
                else:  # 响应读
                    response = read_response_frame(request, "start")
                    print("003:",response)
                connection.sendall(response)
    finally:
        # 清理连接
        connection.close()

    三、关于MC协议的整体实现

    通过“二”我们实现了一个基于MC协议的保持寄存器的读写服务器但并没有像pymodbus这种现成模块那样完整实现这里探讨一下还可以做的事。

    1、SLMP 3E帧实现步骤

    实现SLMPSeamless Message Protocol 3E帧协议涉及到网络通信、数据处理、错误处理等多个步骤。以下是实现SLMP 3E帧的一般步骤

    1建立TCP连接

    在服务端监听指定端口通常是4999。
    在客户端连接到服务端的IP地址和端口。
    2接收请求

    服务端接收客户端发送的SLMP 3E帧请求。
    解析SLMP 3E帧获取命令码、子命令码、数据等信息。
    3处理请求

    根据SLMP 3E帧中的命令码和数据执行相应的操作如读取、写入、控制等。
    处理请求可能涉及到对PLC或其他设备进行读写操作具体实现根据设备和应用需求而定。
    4生成响应

    根据请求处理的结果生成SLMP 3E帧的响应数据。
    设置响应帧的命令码、子命令码、数据等。
    5发送响应

    将生成的SLMP 3E帧响应数据发送回客户端。
    6错误处理

    在处理请求和生成响应的过程中可能出现各种错误如无效命令、数据不合法等。
    针对不同的错误情况生成相应的错误响应帧。
    7关闭连接

    当通信结束或出现错误时关闭TCP连接释放资源。
    请注意SLMP 3E帧协议具体的实现步骤和数据格式可能因具体设备和应用而有所不同。在实际开发中需要参考设备文档和SLMP协议规范来进行具体的实现。

    2、SLMP协议规范

    查阅三菱PLC关于SLMP的文档

    SLMP的详细规范通常由设备厂商提供以便开发者能够正确地使用该协议与设备进行通信。规范文件通常包含SLMP协议的命令码、数据格式、通信流程、错误处理等方面的详细信息。

    3、为什么会有SLMP协议

    SLMPSeamless Message Protocol协议是为了在自动化领域例如工业自动化、制造业、机器人技术等中实现设备之间的无缝通信而设计的。它提供了一种标准化的通信协议使不同厂商、不同类型的设备能够在同一个网络上进行通信实现设备的互联互通。

    在现代工业自动化系统中通常涉及到各种各样的设备这些设备由不同的厂商制造可能使用不同的通信协议和数据格式。为了实现这些设备之间的互联互通需要一种通用的、标准化的通信协议。SLMP就是为了满足这种需求而被开发出来的。

    SLMP协议的设计目标包括

    标准化通信 提供一种通用的通信协议使得不同厂商生产的设备可以在同一个网络上进行通信。

    灵活性 允许不同类型的数据例如状态信息、控制命令等通过同一个协议进行传输。

    高效性 设计为高效的通信协议以满足工业自动化系统对实时性和响应速度的要求。

    易用性 设计为易于实现和配置使得工程师能够方便地将SLMP协议集成到他们的设备和系统中。

    综上所述SLMP协议的存在使得不同类型的自动化设备能够方便地相互通信实现了工业自动化系统的互操作性和灵活性。

    4、我是否可以自定义一套协议

    你完全可以自定义一套通信协议以满足特定需求或者应用场景。自定义通信协议通常涉及到以下几个步骤

    确定通信需求 首先你需要明确通信双方之间需要传输哪些数据以及数据的格式和类型。确定通信的数据结构、命令类型、错误处理机制等。

    选择传输方式 确定通信采用的传输方式可以是基于串口的通信例如RS-232、RS-485、基于网络的通信例如TCP/IP、UDP、无线通信例如Wi-Fi、蓝牙等。

    制定协议规范 定义协议的数据帧格式包括帧头、帧尾、校验码等信息。确保通信双方遵循相同的协议规范。

    实现协议解析和封装 在通信的发送端和接收端分别实现协议的封装和解析逻辑。封装就是将待发送的数据按照协议格式组织成数据帧解析则是在接收端将接收到的数据帧按照协议格式解析成可处理的数据。

    添加错误处理和安全性 考虑数据传输中可能出现的错误情况设计相应的错误处理机制确保数据的完整性和可靠性。如果通信需要保密性可以考虑加密通信数据。

    测试和验证 在实际环境中进行测试和验证确保自定义协议能够正常工作并且满足通信需求。

    请注意自定义协议需要考虑通信的稳定性、可靠性和安全性。在设计过程中建议参考现有通信协议的设计经验以及相关领域的最佳实践。同时文档化自定义协议的规范以便未来的维护和扩展。

  • 阿里云国际版折扣https://www.yundadi.com

  • 阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
    标签: python