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

相关推荐
Ray Liang3 小时前
用六边形架构与整洁架构对比是伪命题?
java·python·c#·架构设计
Scout-leaf3 天前
WPF新手村教程(三)—— 路由事件
c#·wpf
用户298698530143 天前
程序员效率工具:Spire.Doc如何助你一键搞定Word表格排版
后端·c#·.net
mudtools4 天前
搭建一套.net下能落地的飞书考勤系统
后端·c#·.net
玩泥巴的5 天前
搭建一套.net下能落地的飞书考勤系统
c#·.net·二次开发·飞书
唐宋元明清21885 天前
.NET 本地Db数据库-技术方案选型
windows·c#
郑州光合科技余经理5 天前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php
lindexi5 天前
dotnet DirectX 通过可等待交换链降低输入渲染延迟
c#·directx·d2d·direct2d·vortice
feifeigo1235 天前
matlab画图工具
开发语言·matlab
dustcell.5 天前
haproxy七层代理
java·开发语言·前端