上位机监控接收数据(从站)-Modbus TCP 从机(Slave)模式多站点设计

为什么上位机做 "被动接收、等设备发数据" 时,要叫 从站(Slave)

这是很多人搞不懂的核心误区,我一句话先点破:

🔥 终极结论(必须背下来)

** 谁被动等消息 → 谁就是从站(Slave)

谁主动发请求 → 谁就是主站(Master)**


终极完整版:Modbus TCP 从机(Slave)多站点(1、2)

支持:C# + VB.NET

解决:2 个站点、接收数据自动区分、不用第三方模拟器


核心原理(一句话)

  • 1 个 TCP Slave 端口 = 可支持无数个站点号(Unit ID 1~247)
  • 不用开 2 个端口!不用建 2 个 Slave!
  • 接收时直接从消息里取 UnitId 就知道是 1 号还是 2 号

一、C# 完整代码(复制直接运行)

csharp

运行

复制代码
using System;
using System.Net;
using System.Net.Sockets;
using Modbus;
using Modbus.Data;
using Modbus.Device;
using Modbus.Message;

namespace ModbusTcpSlaveMultiUnit
{
    class Program
    {
        static void Main(string[] args)
        {
            var factory = new ModbusFactory();

            // 创建 1 个 TCP 从机(支持所有站点号)
            var slave = factory.CreateTcpSlave(false);

            // ======================
            // 关键:启用多站点支持
            // ======================
            slave.DataStore = new MultiUnitDataStore();

            // 给站点 1 初始化寄存器
            slave.DataStore.SetDataStore(1, DataStoreFactory.CreateDefaultDataStore());
            slave.DataStore.GetDataStore(1).HoldingRegisters[0] = 1111; // 站点1 初始值

            // 给站点 2 初始化寄存器
            slave.DataStore.SetDataStore(2, DataStoreFactory.CreateDefaultDataStore());
            slave.DataStore.GetDataStore(2).HoldingRegisters[0] = 2222; // 站点2 初始值

            // 监听端口 502
            slave.ListenAsync(new IPEndPoint(IPAddress.Any, 502)).Wait();
            Console.WriteLine("Modbus TCP Slave 已启动:端口 502,支持站点 1、2");

            // 接收消息(自动区分站点)
            slave.ModbusMessageReceived += (s, e) =>
            {
                var msg = e.Message;
                byte unitId = msg.SlaveAddress; // 这里就是站点号 1 或 2
                string func = msg.FunctionCode.ToString();

                Console.WriteLine($"\n【收到消息】站点:{unitId}  功能码:{func}");

                if (msg is ReadHoldingRegistersRequest request)
                {
                    Console.WriteLine($"读地址:{request.StartAddress}  长度:{request.NumberOfPoints}");
                }
            };

            Console.ReadLine();
        }
    }
}

二、VB.NET 完整代码

vb

复制代码
Imports System.Net
Imports Modbus
Imports Modbus.Data
Imports Modbus.Device
Imports Modbus.Message

Module ModbusSlaveVB
    Sub Main()
        Dim factory As New ModbusFactory()

        ' 创建 TCP 从机
        Dim slave As IModbusTcpSlave = factory.CreateTcpSlave(False)

        ' 多站点支持
        slave.DataStore = New MultiUnitDataStore()

        ' 站点 1
        slave.DataStore.SetDataStore(1, DataStoreFactory.CreateDefaultDataStore())
        slave.DataStore.GetDataStore(1).HoldingRegisters(0) = 1111

        ' 站点 2
        slave.DataStore.SetDataStore(2, DataStoreFactory.CreateDefaultDataStore())
        slave.DataStore.GetDataStore(2).HoldingRegisters(0) = 2222

        ' 监听 502 端口
        slave.ListenAsync(New IPEndPoint(IPAddress.Any, 502)).Wait()
        Console.WriteLine("Modbus TCP Slave 已启动,支持站点 1、2")

        ' 接收事件(自动区分站点)
        AddHandler slave.ModbusMessageReceived, Sub(s, e)
                                                     Dim msg As IModbusMessage = e.Message
                                                     Dim unitId As Byte = msg.SlaveAddress
                                                     Dim func As String = msg.FunctionCode.ToString

                                                     Console.WriteLine($"站点:{unitId} 功能码:{func}")
                                                 End Sub

        Console.ReadLine()
    End Sub
End Module

三、最关键:如何区分站点 1 / 站点 2

看这一行代码:

csharp

运行

复制代码
byte unitId = msg.SlaveAddress; // 1 或 2

vb

复制代码
Dim unitId As Byte = msg.SlaveAddress

PLC 发过来的消息自带站点号,你直接读取即可!


四、你问的 4 个问题,全部解决

1)两个站点怎么做?

csharp

运行

复制代码
slave.DataStore.SetDataStore(1, ...);
slave.DataStore.SetDataStore(2, ...);

2)接收数据如何区分?

csharp

运行

复制代码
msg.SlaveAddress → 1 或 2

3)需要开多个端口吗?

不用!一个端口 502 支持 1~247 所有站点!

4)还需要 Modbus Slave 模拟器吗?

不需要!你这段代码 = 完整从机模拟器


五、最强总结(你一定能懂)

  • 1 个端口 = 无数站点
  • 站点号 = SlaveAddress
  • 接收时直接判断站点
  • 自己写的软件 = 完全替代第三方模拟器

如果你需要,我还能给你: ✅ 读写寄存器完整示例数据变化事件(值被 PLC 修改时触发)Windows 窗体版(界面显示站点 1/2 数据)

slave.DataStore.GetDataStore(1).HoldingRegisters0 = 1111; // 站点1 初始值 如何指定地址数量?站点1初始值不是地址值?不用多余代码

核心答案(一句话)

HoldingRegisters 0 = 地址 0 HoldingRegisters 1 = 地址 1 数组下标 = 寄存器地址

你要指定多少个地址、赋什么初始值 ,直接给数组赋值就行,不用多余代码


一、如何指定地址数量(最简单)

NModbus4 从机默认给你 1000 个保持寄存器地址(足够用)

相关推荐
上海云盾-小余2 小时前
游戏端口隐蔽防护:端口映射 + 高防集群拦截爆破实操指南
网络·安全·web安全·游戏
计算机安禾2 小时前
【算法分析与设计】第48篇:流算法与数据概要技术
java·服务器·网络·数据库·算法
代码中介商2 小时前
HTTP 完全指南(二):缓存机制深度详解
网络协议·http·缓存
戴西软件2 小时前
戴西CAxWorks.AICrash:AI+法规驱动的行人保护自动化分析
linux·运维·网络·人工智能·安全·自动化
awu的Android笔记3 小时前
Android 弱网模拟:别只会用均匀分布——三种延迟模型和两种丢包模型的原理与实现
android·tcp/ip
打码人的日常分享3 小时前
信息化数据安全管理制度办法(Word)
大数据·运维·网络·云计算·制造
li35743 小时前
深入理解 Linux eBPF 技术——从内核观测到可编程网络
linux·网络
ふり3 小时前
测试的“三重境界”:黑盒、白盒、灰盒的对比与实践
网络·python·测试工具·需求分析
IT大白鼠3 小时前
BGP协议概述:定义、机制与应用
网络·网络协议·华为