C# 实现 Modbus TCP 通信

C# 实现 Modbus TCP 通信 结合主流开源库与底层协议实现

一、核心实现方案

1. 使用 NModbus 库(推荐)

安装依赖

bash 复制代码
Install-Package NModbus  # NuGet 安装

客户端代码示例

c# 复制代码
using System.Net.Sockets;
using Modbus.Device;

public class ModbusTcpClient
{
    public static void Main()
    {
        using TcpClient client = new TcpClient("192.168.0.100", 502); // 连接设备
        var master = ModbusTcpMaster.CreateIp(client);  // 创建 Modbus 主机实例

        // 读取保持寄存器(地址0开始的10个寄存器)
        ushort[] registers = master.ReadHoldingRegisters(0, 10);  
        foreach (var reg in registers)
        {
            Console.WriteLine($"寄存器值: {reg}");
        }
        client.Close();  // 关闭连接
    }
}

关键点

  • ReadHoldingRegisters():读取保持寄存器(功能码 0x03)
  • WriteSingleRegister():写入单个寄存器(功能码 0x06)
  • 自动处理 MBAP 报文头(事务ID、协议ID等)

2. 手动实现协议帧(理解底层)

请求帧结构

字段 事务ID (2B) 协议ID (2B) 长度 (2B) 单元ID (1B) 功能码 (1B) 数据 (N B)
示例 0x00 0x01 0x00 0x00 0x00 0x06 0x01 0x03 起始地址+数量

代码实现

c# 复制代码
// 构建读寄存器请求帧 (功能码 0x03)
byte[] BuildReadRequest(ushort startAddr, ushort count)
{
    byte[] frame = new byte[12];
    // MBAP 头
    frame[0] = 0x00; frame[1] = 0x01;  // 事务ID
    frame[4] = 0x00; frame[5] = 0x06;  // 长度 = 6字节
    frame[6] = 0x01;                   // 单元ID
    // PDU 部分
    frame[7] = 0x03;                   // 功能码
    frame[8] = (byte)(startAddr >> 8); // 起始地址高字节
    frame[9] = (byte)startAddr;        // 起始地址低字节
    frame[10] = (byte)(count >> 8);    // 寄存器数量高字节
    frame[11] = (byte)count;           // 寄存器数量低字节
    return frame;
}

// 发送请求并解析响应
TcpClient client = new TcpClient("127.0.0.1", 502);
NetworkStream stream = client.GetStream();
stream.Write(requestFrame, 0, requestFrame.Length);

byte[] response = new byte[256];
int bytesRead = stream.Read(response, 0, response.Length);
// 解析响应数据(略)

优势:深入理解协议细节,适合定制化场景。


二、进阶功能

1. 服务端实现(模拟设备)
c# 复制代码
using NModbus;
using NModbus.Tcp;

var listener = new TcpListener(IPAddress.Any, 502);
listener.Start();
while (true)
{
    TcpClient client = listener.AcceptTcpClient();
    var factory = new ModbusFactory();
    var slave = factory.CreateSlave(1); // 从站地址=1
    
    // 绑定寄存器数据存储区
    slave.DataStore = new ModbusDataStore(); 
    slave.DataStore.HoldingRegisters[0] = 1234; // 初始化寄存器值
    
    Task.Run(() => slave.Listen(client.GetStream())); // 异步处理请求
}

应用场景:设备仿真、测试上位机逻辑。

2. 错误处理与重连
c# 复制代码
try
{
    master.WriteSingleRegister(0, 100); // 写入寄存器
}
catch (SocketException ex)
{
    Console.WriteLine($"网络错误: {ex.Message}");
    Reconnect(client); // 重连逻辑
}
catch (ModbusException ex)
{
    Console.WriteLine($"Modbus错误码: {ex.ErrorCode}");
}
3. 批量操作优化
c# 复制代码
// 一次读取多个寄存器(减少请求次数)
ushort[] batchData = master.ReadHoldingRegisters(0, 50);

// 批量写入寄存器
master.WriteMultipleRegisters(0, new ushort[]{10, 20, 30});

四、扩展应用

  1. 多设备管理

    使用 Dictionary<string, TcpClient>管理多个设备连接。

  2. 安全通信

    通过 VPN 或 TLS 加密隧道(需设备支持)。

  3. 与工业系统集成

    • 读取 PLC 数据(如西门子 S7-1200)
    • 连接 SCADA 系统(如 Ignition、WinCC)。

🔗 五、资源推荐

  1. 源码推荐
  2. 调试工具
    • Modbus Poll(测试客户端)
    • Wireshark(抓包分析协议帧)

完整示例代码:NModbus 官方示例 github.com/NModbus/NModbus/tree/master/src/Samples

协议文档:Modbus TCP 规范 modbus.org/docs/Modbus_Messaging_Implementation_Guide_V1_0b.pdf

相关推荐
程序喵大人7 小时前
【C++进阶】STL容器与迭代器 - 01 STL 容器先解决元素放在哪里
开发语言·c++·stl
cui_ruicheng8 小时前
Python从入门到实战(十六):多进程编程
开发语言·python
wdfk_prog9 小时前
嵌入式面试真题第 15 题:不可恢复异常后的通用崩溃快照、调用栈保存与离线分析架构
linux·开发语言·面试·架构
晴空了无痕9 小时前
从 Go 基础到 K8s:一条可落地的 Go 服务端成长路线
开发语言·后端·golang·kubernetes
神明不懂浪漫9 小时前
【第五章】Java中的继承与多态
java·开发语言
神州世通10 小时前
解密企业通信安全防线:Avaya Aura 三层安全架构深度解析
开发语言·php
AC赳赳老秦11 小时前
企业工商公开信息采集分析:OpenClaw 批量查询企业工商信息,生成企业画像报告
大数据·开发语言·python·自动化·php·deepseek·openclaw
qq_25183645712 小时前
基于java Web 动漫视频网站毕业论文
java·开发语言·前端
野生风长12 小时前
C++入门基础:从命名空间到引用与指针的全面解析
开发语言·c++