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

相关推荐
浅念-4 小时前
C语言编译与链接全流程:从源码到可执行程序的幕后之旅
c语言·开发语言·数据结构·经验分享·笔记·学习·算法
小宋10214 小时前
Java 项目结构 vs Python 项目结构:如何快速搭一个可跑项目
java·开发语言·python
一晌小贪欢5 小时前
Python 爬虫进阶:如何利用反射机制破解常见反爬策略
开发语言·爬虫·python·python爬虫·数据爬虫·爬虫python
阿猿收手吧!5 小时前
【C++】异步编程:std::async终极指南
开发语言·c++
小程故事多_805 小时前
Agent Infra核心技术解析:Sandbox sandbox技术原理、选型逻辑与主流方案全景
java·开发语言·人工智能·aigc
沐知全栈开发5 小时前
SQL 日期处理指南
开发语言
黎雁·泠崖5 小时前
【魔法森林冒险】3/14 Allen类(一):主角核心属性与初始化
java·开发语言
黎雁·泠崖5 小时前
【魔法森林冒险】1/14 项目总览:用Java打造你的第一个回合制冒险游戏
java·开发语言
独好紫罗兰5 小时前
对python的再认识-基于数据结构进行-a006-元组-拓展
开发语言·数据结构·python
C++ 老炮儿的技术栈6 小时前
Qt 编写 TcpClient 程序 详细步骤
c语言·开发语言·数据库·c++·qt·算法