有些业务场景不适合异步获取信息,可以使用主动轮询+同步获取的方式获取OPC信息


using OPCAutomation;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Net;
using LitJson;

namespace XSDLOPCClinet
{
    public partial class Form1 : Form
    {
        /*---------------------------静态变量及全局对象段-----------------------*/
        OPCServer ObjOPCServer;
        OPCGroups ObjOPCGroups;
        OPCGroup ObjOPCGroup;
        static string OPCServerName = "Kepware.KEPServerEX.V5";// 服务器名称
        static string OPCip = "127.0.0.1";// 服务器IP地址
        const string DesignLife = "db500dbd450";// 刀具设定寿命地址
        const string ActualLife = "dbd500dbd454";// 刀具实际寿命地址
        const string ToolName = "dbd500dbW428";// 刀具名称地址
        // 数据库配置信息
        /*public static string uid = "sa";
        public static string psw = "W991224z";
        public static string initialcatalog = "test2";
        public static string Server = "10.4.51.87\\MYNEWSQL";
        public static string timeout = "3"; // 等待时间太长会导致连接失败情况下程序"假死"
        */
        public const string sqloptions = "uid=sa;password=W991224z;initial catalog = test2;Server=10.4.51.87\\MYNEWSQL;Connect Timeout=3";
       
        // 变量声明
        private OPCItem[] OPC_ITEMS_ADDED;// 声明item添加函数名
        Dictionary<string, string> MAP_CLIENTHANDLE_TAG = new Dictionary<string, string>();// 创建字典用于绑定TAG和地址,这里使用全称访问
        Dictionary<string, string> tagValueMap = new Dictionary<string, string>();// 绑定TAG和数据信息
        List<string> l_str = new List<string>();// 用于存放设备名称
        List<OPCItem> ItemsAdded = new List<OPCItem>();// 用于存放设备item/地址信息
        // 定义委托
        public delegate void Handlelist();
        /*--------------------------以下为程序段-----------------------------*/
        // 窗体初始化
        public Form1()
        {
                InitializeComponent();
               
        }
        // 启动连接,之后进行设备信息初始化操作
        private void InitServer()
        {
            ObjOPCServer = new OPCServer();
            ObjOPCServer.Connect(OPCServerName, OPCip);
            if (ObjOPCServer.ServerState == (int)OPCServerState.OPCRunning)
            {
                label1.Text = $"OPC服务器名:{ObjOPCServer.ServerName}";
                label4.Text = $"连接启动时间:{ObjOPCServer.StartTime.ToString()}";
                label3.Text = "服务运行中,请勿关闭";
                //创建并设置组
                bool bSucce = this.InitGetDataConfig();
                //添加设备信息
                GetDeviceGroup();
                //group添加items
                bool addItems = AddGroupItems();
                //初始化Tag字典
                bool tagDictionary = InitTagValueMap();
                //采集opc数据
                bool Sync = InitTimer();
                //GetOPCData();
                bool Alert = InitAutoAlart();
            }
            else
            {
                label3.Text = "OPC服务器状态异常: " + ObjOPCServer.ServerState.ToString();
            }
        }
        // 初始化OPC驱动配置
        private bool InitGetDataConfig()
        {
            ObjOPCGroups = ObjOPCServer.OPCGroups;
            ObjOPCGroup = ObjOPCGroups.Add();// 初始化Groups组
            //ObjOPCGroup.DataChange += new DIOPCGroupEvent_DataChangeEventHandler(GroupAsyncReadComplete);
            //ObjOPCGroup.IsActive = true;
            //ObjOPCGroup.IsSubscribed = true;
            //ObjOPCServer.OPCGroups.DefaultGroupDeadband = 3;// 死区值,设为0时,服务器端该组内任何数据变化都通知组
            return true;
        }
        // 初始化tagValueMap(Tag与数据容器)
        private bool InitTagValueMap()
        {
            foreach(string tag in l_str)
            {
                string address1 = $"{tag}.{DesignLife}";// 刀具设定寿命
                string address2 = $"{tag}.{ActualLife}";// 刀具实际寿命
                string address3 = $"{tag}.{ToolName}";// 刀具名称
                tagValueMap.Add(address1,"");
                tagValueMap.Add(address2, "");
                tagValueMap.Add(address3, "");
            }
            return true;
        }
        // 获取设备信息
        private void GetDeviceGroup()
        {
            l_str.Add("10A.PLC.");
            l_str.Add("10B.PLC.");
            l_str.Add("10C.PLC.");
            l_str.Add("10D.PLC.");
            l_str.Add("20A.PLC.");
            l_str.Add("20B.PLC.");
            l_str.Add("20C.PLC.");
            l_str.Add("20D.PLC.");
            l_str.Add("20E.PLC.");
            l_str.Add("20F.PLC.");
            l_str.Add("30A.PLC.");
            l_str.Add("30B.PLC.");
            l_str.Add("30C.PLC.");
            l_str.Add("30D.PLC.");
            l_str.Add("30E.PLC.");
            l_str.Add("30F.PLC.");
            l_str.Add("40A.PLC.");
            l_str.Add("40B.PLC.");
            l_str.Add("40C.PLC.");
            l_str.Add("40D.PLC.");
            l_str.Add("40E.PLC.");
            l_str.Add("40F.PLC.");
            l_str.Add("80A.PLC.");
            l_str.Add("80B.PLC.");
            l_str.Add("80C.PLC.");
            l_str.Add("80D.PLC.");
            l_str.Add("80E.PLC.");
            l_str.Add("80F.PLC.");
            
        }
        // 添加Item值(address)
        private bool AddGroupItems()
        {
            try
            {
                int n = 0;
                foreach (string tag in l_str)
                {
                    string address1 = $"{tag}{DesignLife}";// 刀具设定寿命
                    string address2 = $"{tag}{ActualLife}";// 刀具实际寿命
                    string address3 = $"{tag}{ToolName}";// 刀具名称

                    ItemsAdded.Add(ObjOPCGroup.OPCItems.AddItem(address1, n));
                    ItemsAdded.Add(ObjOPCGroup.OPCItems.AddItem(address2, n + 1));
                    ItemsAdded.Add(ObjOPCGroup.OPCItems.AddItem(address3, n + 2));
                    //clientHandle tag关系
                    MAP_CLIENTHANDLE_TAG.Add(n + "", address1);
                    MAP_CLIENTHANDLE_TAG.Add(n + 1 + "", address2);
                    MAP_CLIENTHANDLE_TAG.Add(n + 2 + "", address3);
                    n = n + 3;
                }
                OPC_ITEMS_ADDED = ItemsAdded.ToArray();
            }
            catch (Exception e)
            {

            }


            return true;
        }
        // 初始化主动轮询计时器
        private bool InitTimer()
        {
            System.Timers.Timer t = new System.Timers.Timer(1000);//实例化Timer类,设置间隔时间为1000毫秒; 
            t.Elapsed += new System.Timers.ElapsedEventHandler(OrderTimer_Tick);//到时间的时候执行事件; 
            t.AutoReset = true;//设置是执行一次(false)还是一直执行(true); 
            t.Enabled = true;//是否执行System.Timers.Timer.Elapsed事件; 
            return true;
        }
        // 设置自动报警定时器
        private bool InitAutoAlart()
        {
            System.Timers.Timer p = new System.Timers.Timer(50000);//实例化Timer类,设置间隔时间为5分钟; 
            p.Elapsed += new System.Timers.ElapsedEventHandler(AutoAlert);//到时间的时候执行事件; 
            p.AutoReset = true;//设置是执行一次(false)还是一直执行(true); 
            p.Enabled = true;//是否执行System.Timers.Timer.Elapsed事件; 
            return true;
        }
        // 定时报警,查询数据库报警列表,通知golang,去调用钉钉接口
        public void AutoAlert(object source, System.Timers.ElapsedEventArgs e)
        {
            SqlConnection objConnection = new SqlConnection(sqloptions);
            objConnection.Open();
            string sql = "SELECT * FROM AlertList";
            SqlCommand cmd = new SqlCommand(sql, objConnection);
            SqlDataReader dr = cmd.ExecuteReader();
            if (dr.HasRows)
            {
                while (dr.Read())
                {
                    try
                    {
                        AlertGolang(dr["MachineCode"].ToString(), dr["ToolName"].ToString(), dr["DesignLife"].ToString(), dr["ActualLife"].ToString(), "1");
                    }
                    catch(Exception ex)
                    {
                       
                    }
                }
            }
            dr = null;
            cmd = null;
            sql = null;
            objConnection.Close();
        }
        // 定时轮询
        public void OrderTimer_Tick(object source, System.Timers.ElapsedEventArgs e)
        {
            Handlelist m = new Handlelist(InvokedFunc);
            Invoke(m);
        }
        // 被委托的方法
        private void InvokedFunc()
        {
            SyncRead();
        }
        // 同步读
        private void SyncRead()
        {

            int[] temp = new int[OPC_ITEMS_ADDED.Length + 1];
            temp[0] = 0;
            for (int i = 1; i <= OPC_ITEMS_ADDED.Length; i++)
            {
                temp[i] = OPC_ITEMS_ADDED[i - 1].ServerHandle;
            }
            Array serverHandles = (Array)temp;
            ObjOPCGroup.SyncRead((short)OPCDataSource.OPCDevice, serverHandles.Length - 1, ref serverHandles, out Array Values, out Array Errors, out object Qualities, out object TimeStamps);
            // 字典Key,Value绑定
            int j = 1;
            foreach (string tag in l_str)
            {
                tagValueMap[$"{tag}{DesignLife}"] = Values.GetValue(j).ToString();
                tagValueMap[$"{tag}{ActualLife}"] = Values.GetValue(j + 1).ToString();
                tagValueMap[$"{tag}{ToolName}"] = Values.GetValue(j + 2).ToString();
                j = j + 3;
                string sql = $"UPDATE Toolsinfo set ActualLife = '{tagValueMap}',DesignLife = '{tagValueMap}' WHERE MachineCode = '{tag.Substring(0,3)}' AND ToolName = '{tagValueMap}'";
                try {
                    Set(sql);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
            
        }
        // 异步读取信息实现(因业务需求,存在相同数据,废弃)
        /*private void GetOPCData()
        {
            try
            {
                //异步读opc数据
                int[] temp = new int[OPC_ITEMS_ADDED.Length + 1];
                temp[0] = 0;
                for (int i = 1; i <= OPC_ITEMS_ADDED.Length; i++)
                {
                    temp[i] = OPC_ITEMS_ADDED[i - 1].ServerHandle;
                }
                Array serverHandles = (Array)temp;
                Array Errors;
                int cancelID;
                Random rd = new Random();
                int TransactionID = rd.Next(1, 100);
                ObjOPCGroup.AsyncRead(serverHandles.Length - 1, ref serverHandles, out Errors, TransactionID, out cancelID);//第一参数为item数量
            }
            catch (Exception ex)
            {

                MessageBox.Show(ex.Message + "cuowu");
            }
        }*/
        // 异步获取t,v信息(废弃)
        /*private void GroupAsyncReadComplete(int TransactionID, int NumItems, ref Array ClientHandles, ref Array ItemValues, ref Array Qualities, ref Array TimeStamps)
        {

            //C# Dictionary 字典 
             
               
                for (int i = 1; i <= NumItems; i++)
                {
                    string clientHandle = ClientHandles.GetValue(i).ToString();
                    string tag = MAP_CLIENTHANDLE_TAG[clientHandle];
                    string val = ItemValues.GetValue(i).ToString();
                    tagValueMap.Add(tag, val);
                try
                {
                    listBox1.Items.Add(tagValueMap[$"10A.PLC.{ToolName}"]);
                    listBox1.Items.Add(tagValueMap[$"10A.PLC.{DesignLife}"]);
                    listBox1.Items.Add(tagValueMap[$"10A.PLC.{ActualLife}"]);
                    listBox1.Items.Add(tagValueMap[$"10B.PLC.{ToolName}"]);
                    listBox1.Items.Add(tagValueMap[$"10C.PLC.{DesignLife}"]);
                    listBox1.Items.Add(tagValueMap[$"10D.PLC.{ActualLife}"]);
                }
                catch (Exception e)
                {
                    
                }

                //C# Dictionary 字典 添加数据
                //MessageBox.Show(tag);
            }
            
            // 在这里可以调用SQL语句进行value值的更新,是异步的,不是同步更新
            //string sql = $"INSERT INTO Toolsinfo (ToolName,DesignLife,ActualLife,MachineCode) values ('{a}','{b}','{c}','10A')";
            //Set(sql);
           




        }
        */
        // 退出时释放资源
        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            ObjOPCServer.Disconnect();
        }
        // 启动按钮
        private void button1_Click(object sender, EventArgs e)
        {
                  InitServer();// 启动服务
                  button1.Enabled = false;
                  button1.Text = "服务已启动";
        }
        // 数据库SET操作
        private void Set(string sql)
        {
            SqlConnection objConnection = new SqlConnection(sqloptions);
            try
            {
                objConnection.Open();
                SqlCommand cmd = new SqlCommand(sql, objConnection);
                cmd.ExecuteScalar();
                objConnection.Close();
            }
            catch (Exception err)
            {
                MessageBox.Show(err.Message);
                objConnection.Close();
            }
            objConnection.Close();
        }
        /*----------------------与Golang交互--------------------------*/
        private void AlertGolang(string MachineCode,string ToolName,string DesignLife,string ActualLife,string warnLevel)
        {
            ReadOptions Read = new ReadOptions();
            string Gosrv = Read.Readini("Srv", "DBsrv");
            string Goport = Read.Readini("Srv", "DBport");
            string GoRouter = Read.Readini("Router","Ding");
            Encoding encode = Encoding.GetEncoding("utf-8");
            JsonData parmas = new JsonData
            {
                ["Code"] = warnLevel,
                ["MachineCode"] = MachineCode,
                ["ToolName"] = ToolName,
                ["DesignLife"] = DesignLife,
                ["ActualLife"] = ActualLife
            };
            string jsonData = JsonMapper.ToJson(parmas);
            HttpWebRequest myReq = null;
            HttpWebResponse response = null;
            byte[] postdatabyte = Encoding.UTF8.GetBytes(jsonData);
            myReq = (HttpWebRequest)WebRequest.Create($"http://{Gosrv}:{Goport}/{GoRouter}");
            myReq.Method = "POST";
            myReq.ContentType = "application/json; charset=UTF-8";
            myReq.ContentLength = postdatabyte.Length;
            Stream toPost = myReq.GetRequestStream();
            toPost.Write(postdatabyte, 0, postdatabyte.Length);
            toPost.Close();
            response = (HttpWebResponse)myReq.GetResponse();
            var responseString = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("utf-8")).ReadToEnd();
            Read = null;
        }
        /*-----------------------菜单栏-------------------------------*/
        private void 增加设备刀具信息ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (button1.Enabled == false)
            {
                MessageBox.Show("服务运行中,请在停止服务后使用此功能!");
            }
            else
            {
                Form2 objFrom = new Form2();
                objFrom.ShowDialog();
            }
           
        }
    }
}

原文地址:http://www.cnblogs.com/wz0130/p/16905496.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性