让你的PLC支持多连接,多电脑同时访问一个PLC 连接PLC的权限设置,PLC同时多连接

要明白一个技术,首先要明白它到底是解决什么问题的?你是不是有以下的困扰
1. 我有个三菱的PLC,只能配置一个端口,但是有多台电脑需要从PLC进行读写,因为三菱是单链接的,所以直接读写会报错。

2. 我得三菱PLC不希望对所有的客户端都开放权限读写,比如输入正确的用户名密码,才能通信

3. 我得PLC是在一个很小型的现场组网的,和公司内网不一个网络,但是有个工控机既连着PLC,也连着公司内网,但是内网的客户端程序也需要读写PLC,这时候也可以使用下面的注册PLC功能来解决

 

好了,有了这个需求,我们再来看怎么操作。依旧是使用hslcommunication组价

HslCommunication 软件,详细可以参考下面的地址:

github地址:https://github.com/dathlin/HslCommunication

官网:http://www.hslcommunication.cn

加群咨询学习信息:http://www.hslcommunication.cn/

在Visual Studio 中的NuGet管理器中可以下载安装,也可以直接在NuGet控制台输入下面的指令安装如果需要教程:Nuget安装教程:http://www.cnblogs.com/dathlin/p/7705014.html

1
Install-Package HslCommunication

组件的api地址:http://api.hslcommunication.cn

 

 

 

 

我们先写服务器的代码:

新建好控制台项目后,我们就可以安装hslcommunication了

 

 

 

然后就是写代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using HslCommunication;
using HslCommunication.ModBus;
using HslCommunication.MQTT;
using HslCommunication.Profinet.Melsec;
using HslCommunication.Profinet.Siemens;
 
namespace ConsoleApp1
{
    internal class Program
    {
        static void Main( string[] args )
        {
            MqttServer server;
            MelsecMcNet melsec;
            SiemensS7Net siemens;
            ModbusRtu modbus;
 
            melsec = new MelsecMcNet( "118.24.36.220", 6000 );                // ip及端口需要改成你自己实际的参数
            melsec.SetPersistentConnection( );
 
            siemens = new SiemensS7Net( SiemensPLCS.S1200, "118.24.36.220" ); // ip需要改成你自己实际的参数
            siemens.SetPersistentConnection( );
 
            modbus = new ModbusRtu( 1 );                                      // 指定站号实例化
            modbus.SerialPortInni( "COM2", 9600 );                            // 初始化串口信息
            modbus.DataFormat = HslCommunication.Core.DataFormat.CDAB;        // 根据实际情况设置
 
            server = new MqttServer( );
            server.ClientVerification += Server_ClientVerification;           // 启动账户密码,如果不需要验证,则注释即可
 
            server.RegisterMqttRpcApi( "MelsecPLC", melsec );                 // API分类随便写,方便客户端指定就行,需要唯一
            server.RegisterMqttRpcApi( "SiemensPLC", siemens );               // API分类随便写,方便客户端指定就行,需要唯一
            server.RegisterMqttRpcApi( "Modbus", modbus );                    // API分类随便写,方便客户端指定就行,需要唯一
 
            server.ServerStart( 1883 );                                       // 启动服务
            Console.WriteLine( "已经启动" );
            Console.ReadLine( );
        }
 
        private static int Server_ClientVerification( MqttSession mqttSession, string clientId, string userName, string passwrod )
        {
            // 这里举例只能账户密码登录
            // if (userName == "admin" && passwrod == "123456") return 0;
            // else return 1;
 
            //不校验用户名密码
            return 0;
        }
    }
}

  

 我们假设了三种设备需要远程访问的操作。服务器端的代码已经写好了,这时候,这个PLC已经支持从外部直接读写数据了。

 

 

 大致的架构如图所示:

现在我们可以使用客户端来测试是否可以成功访问了,如果端口拒绝连接,则需要检查防火墙是否端口隔离了。

 

我们先打开hslcommunicationdemo测试:如果没有demo的话,从这里下载:http://www.hsltechnology.cn/Home/Download

 

 

 

在这里,为了支持注册多个PLC的数据。每个实体通信对象需要指定一个唯一的识别码,也就是上面服务器注册的三个数据

  • MelsecPLC
  • SiemensPLC
  • Modbus

 

这个数据在客户端时,为了找到唯一的接口对象,则需要指定。也就是Demo测试界面的 设备主题

当然,如果你设备比较多,设备间又有层级的概念,所以使用分隔符 / 来区分,例如

  • 分厂一/车间A/硫化机A01
  • 分厂一/车间A/硫化机A02
  • 分厂一/车间B/成型机B01

 

我们已经在demo客户端上测试成功。那么我们用代码怎么写呢?

同样是新建一个控制台项目,安装 hslcommunication组件,然后写入代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using HslCommunication;
using HslCommunication.Core;
using HslCommunication.LogNet;
using HslCommunication.Profinet.GE;
using HslCommunication.BasicFramework;
using System.IO.Ports;
using HslCommunication.MQTT;
 
namespace NetFrameworkConsole
{
    class Program
    {
        static void Main( string[] args )
        {
            // 我们接下来在客户端访问当前的数据信息
            MqttRpcDevice rpcMelsec = new MqttRpcDevice( new MqttConnectionOptions( )
            {
                IpAddress = "127.0.0.1",    // 服务器的IP地址
                Port = 1883,
                Credentials = new MqttCredential( "admin", "123456" ),  // 如果配置了用户名密码
                UseRSAProvider = true,                                  // 是否加密通信
            },
                "MelsecPLC" );
 
            MqttRpcDevice rpcSiemens = new MqttRpcDevice( new MqttConnectionOptions( )
            {
                IpAddress = "127.0.0.1",    // 服务器的IP地址
                Port = 1883,
                Credentials = new MqttCredential( "admin", "123456" ),  // 如果配置了用户名密码
                UseRSAProvider = true,                                  // 是否加密通信
            },
                "SiemensPLC" );
 
            MqttRpcDevice rpcModbus = new MqttRpcDevice( new MqttConnectionOptions( )
            {
                IpAddress = "127.0.0.1",    // 服务器的IP地址
                Port = 1883,
                Credentials = new MqttCredential( "admin", "123456" ),  // 如果配置了用户名密码
                UseRSAProvider = true,                                  // 是否加密通信
            },
                "Modbus" );
 
            // 就可以进行读取了,例如读取三菱设备的D100的short值
            OperateResult write1 = rpcMelsec.Write( "D100", (short)123 );
            OperateResult<short> read1 = rpcMelsec.ReadInt16( "D100" );
            Console.WriteLine( "Read Value1 D100: " + read1.Content );
 
            // 例如读取西门设备的float值
            OperateResult write2 = rpcSiemens.Write( "M100", 1.23f );
            OperateResult<float> read2 = rpcSiemens.ReadFloat( "M100" );
            Console.WriteLine( "Read Value2 M100: " + read2.Content );
 
            // Modbus设备读取int值
            OperateResult write3 = rpcModbus.Write( "100", 123 );
            OperateResult<int> read3 = rpcModbus.ReadInt32( "100" );
            Console.WriteLine( "Read Value3 100: " + read3.Content );
 
            // 用法上和普通的三菱,西门子,modbus是没有区别的。
        }
    }
}

  

我们运行它

 

 

嗯,非常好。对客户端来说,支持多个设备的实例化对象,和服务器通信时,对于同一个PLC连接而言,内部会自动加锁通信。

所以这种情况不太适合,很多客户端同时频繁读写PLC,大数据的时候,读取的地址也是一样的。这种情况下,适合服务器先采集PLC数据,自动推送到所有的客户端,这样性能可以好很多。

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using HslCommunication;
using HslCommunication.ModBus;
using HslCommunication.MQTT;
using HslCommunication.Profinet.Melsec;
using HslCommunication.Profinet.Siemens;
 
namespace ConsoleApp1
{
    internal class Program
    {
        static void Main( string[] args )
        {
            MqttServer server;
            MelsecMcNet melsec;
            SiemensS7Net siemens;
            ModbusRtu modbus;
 
            melsec = new MelsecMcNet( "118.24.36.220", 6000 );                // ip及端口需要改成你自己实际的参数
            melsec.SetPersistentConnection( );
 
            siemens = new SiemensS7Net( SiemensPLCS.S1200, "118.24.36.220" ); // ip需要改成你自己实际的参数
            siemens.SetPersistentConnection( );
 
            modbus = new ModbusRtu( 1 );                                      // 指定站号实例化
            modbus.SerialPortInni( "COM2", 9600 );                            // 初始化串口信息
            modbus.DataFormat = HslCommunication.Core.DataFormat.CDAB;        // 根据实际情况设置
 
            server = new MqttServer( );
            server.ClientVerification += Server_ClientVerification;           // 启动账户密码,如果不需要验证,则注释即可
 
            server.RegisterMqttRpcApi( "MelsecPLC", melsec );                 // API分类随便写,方便客户端指定就行,需要唯一
            server.RegisterMqttRpcApi( "SiemensPLC", siemens );               // API分类随便写,方便客户端指定就行,需要唯一
            server.RegisterMqttRpcApi( "Modbus", modbus );                    // API分类随便写,方便客户端指定就行,需要唯一
 
            server.ServerStart( 1883 );                                       // 启动服务
            Console.WriteLine( "已经启动" );
 
            while (true)
            {
                Thread.Sleep( 1000 );
 
                // 读取PLC的数据,并且把数据分发出去
                OperateResult<short> read1 = melsec.ReadInt16( "D100" );
                if (read1.IsSuccess)
                {
                    // 这里的topic没有什么规则,都是自己设定的,注意不和其他数据冲突就行
                    server.PublishTopicPayload( "MelsecPLC.A", Encoding.UTF8.GetBytes( read1.Content.ToString( ) ) );
 
                    Console.WriteLine( DateTime.Now.ToString( ) + " success! " );
                }
                else
                {
                    Console.WriteLine( DateTime.Now.ToString( ) + " failed: " + read1.Message );
                }
            }
        }
 
        private static int Server_ClientVerification( MqttSession mqttSession, string clientId, string userName, string passwrod )
        {
            // 这里举例只能账户密码登录
            // if (userName == "admin" && passwrod == "123456") return 0;
            // else return 1;
 
            //不校验用户名密码
            return 0;
        }
    }
}

新增加的代码就是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
while (true)
{
    Thread.Sleep( 1000 );
 
    // 读取PLC的数据,并且把数据分发出去
    OperateResult<short> read1 = melsec.ReadInt16( "D100" );
    if (read1.IsSuccess)
    {
        // 这里的topic没有什么规则,都是自己设定的,注意不和其他数据冲突就行
        server.PublishTopicPayload( "MelsecPLC.A", Encoding.UTF8.GetBytes( read1.Content.ToString( ) ) );
 
        Console.WriteLine( DateTime.Now.ToString( ) + " success! " );
    }
    else
    {
        Console.WriteLine( DateTime.Now.ToString( ) + " failed: " + read1.Message );
    }
}

  

运行之后的效果:

 

 

 

我们只需要打开hslcommunication的demo,测试mqtt即可。

 

 

实际可以根据情况再进行针对性的优化操作。

 

如果还有什么问题,可以通过最上方的连接找到作者。

 

posted @   dathlin  阅读(16771)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示