近來因爲工程須要,基於OPC DA 2.0搭建通用的取數模塊,與遠程webscoket服務端鏈接,並傳輸數據。在網上找了些資料,修改相應網友公開的源代碼,基本達到要求,特供你們參考。前端
1.實體類web
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace OPC_DEMO { public class MyOPCItem { public string key{ get; set; } public string Value { get; set; } } }
2.源代碼json
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using OPCAutomation; using System.Threading; using System.IO; using WebSocketSharp; using Newtonsoft.Json; namespace OPC_DEMO { public partial class Form1 : Form { private OPCServer KepServer; private OPCGroups KepGroups; private OPCGroup KepGroup; private OPCItems KepItems; public WebSocket wsc; private string JsonStr; private MyOPCItem opc; Dictionary<string, string> MAP_CLIENTHANDLE_TAG; public OPCItem[] OPC_ITEMS_ADDED { get; private set; } public Form1() { InitializeComponent(); } #region OPC Client /// <summary> /// 自動鏈接OPC Server,並websocket鏈接服務器。 /// </summary> private void KepServerLoad() { try { KepServer = new OPCServer(); //KepServer.Connect("FBoxOpcServer", "127.0.0.1"); KepServer.Connect("Kepware.KEPServerEx.V6","127.0.0.1"); // KepServer.Connect("Kepware.KEPServerEx.V5","127.0.0.1"); if (KepServer.ServerState == (int)OPCServerState.OPCRunning) { wsc = new WebSocket("ws://10.0.0.128:6690/WsServices"); wsc.Connect(); richTextBox1.Text = "OPC Server鏈接成功"; } else { richTextBox1.Text = "OPC Server鏈接失敗"; return; } } catch (Exception ex) { richTextBox1.Text = "OPC Server鏈接失敗," + ex.Message; return; } KepGroups = KepServer.OPCGroups; Thread t1; // 開1個線程用於讀取數據 t1 = new Thread(new ThreadStart(KepProcess)); t1.Start(); } /// <summary> /// 新建OPC Group並設置相應的屬性,和觸發改變事件 /// </summary> public void KepProcess() { //KepGroup = KepGroups.Add("Channel.Device.Group"); KepGroup = KepGroups.Add("Channel1.Device1.Group"); KepGroup.UpdateRate = 1000; KepGroup.IsActive = true; KepGroup.IsSubscribed = true; KepItems = KepGroup.OPCItems; AddGroupItems(); //當KepGroup中數據發生改變的觸發事件 KepGroup.DataChange += new DIOPCGroupEvent_DataChangeEventHandler(KepGroup_DataChange); // //item1 = KepItems.AddItem("My FBox.外泵站1.AI.流量1", 1); // item1 = KepItems.AddItem("通道 1.設備 1.標記 1", 1); ////item2 = KepItems.AddItem("My FBox.外泵站1.DI.格柵運行", 2); //item2 = KepItems.AddItem("通道 1.設備 1.標記 2", 2); //item3 = KepItems.AddItem("通道 1.設備 1.test",3); } /// <summary> /// 單獨設立添加OPCItem方法,用來添加OPCItem /// </summary> public void AddGroupItems() { List<string> str = new List<string>(); str.Add("通道 1.設備 1.標記 1"); str.Add("通道 1.設備 1.標記 2"); str.Add("通道 1.設備 1.test"); List<OPCItem> ItemsAdd = new List<OPCItem>(); MAP_CLIENTHANDLE_TAG = new Dictionary<string, string>(); int n = 0; foreach (string tag in str) { ItemsAdd.Add(KepItems.AddItem(tag, n)); MAP_CLIENTHANDLE_TAG.Add(n + "", tag); n++; } OPC_ITEMS_ADDED = ItemsAdd.ToArray(); } //當數據改變時觸發的事件 //public delegate void DelegateShowMessage(string str); public delegate void DelegateShowMessage(MyOPCItem str); /// <summary> /// 數據改變事件觸發編寫,調用委託事件遠程發送。 /// </summary> /// <param name="TransactionID"></param> /// <param name="NumItems"></param> /// <param name="ClientHandles"></param> /// <param name="ItemValues"></param> /// <param name="Qualities"></param> /// <param name="TimeStamps"></param> public void KepGroup_DataChange(int TransactionID, int NumItems, ref Array ClientHandles, ref Array ItemValues, ref Array Qualities, ref Array TimeStamps) { Dictionary<string, string> tagValueMap = new Dictionary<string, string>(); string str = ""; // DelegateShowMessage show1 = new DelegateShowMessage(ShowMessage); DelegateShowMessage show1 = new DelegateShowMessage(ShowMessage); 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(); //C# Dictionary 字典 添加數據 tagValueMap.Add(tag, val); //for (int i = 1; i <= NumItems; i++) //{ // if (ClientHandles.GetValue(i).Equals(1)) // { // str = "通道 1.設備 1.標記 1:" + ItemValues.GetValue(i).ToString(); // } // if (ClientHandles.GetValue(i).Equals(2)) // { // str = "通道 1.設備 1.標記 2:" + ItemValues.GetValue(i).ToString(); // } // if (ClientHandles.GetValue(i).Equals(3)) // { // str = "通道 1.設備 1.test:" + ItemValues.GetValue(i).ToString(); // } } //str = tagValueMap["通道 1.設備 1.標記 1"]; // str = tagValueMap["通道 1.設備 1.標記 2"]; //str = tagValueMap["通道 1.設備 1.標記 test"]; // BeginInvoke(show1, new string[] { str }); MyOPCItem json =ParseOPCData(tagValueMap); BeginInvoke(show1, json); } //public string ParseOPCData(Dictionary<string,string> tagValueMap) //{ // foreach (var item in tagValueMap) // { // string key = item.Key; // var value = item.Value; // return "{"+"key:"+ key + "," + "Value:"+ value+"}"; // } // return ""; //} /// <summary> /// 讀Dictionary中的值,並傳遞給實體類。 /// </summary> /// <param name="tagValueMap"></param> /// <returns></returns> public MyOPCItem ParseOPCData(Dictionary<string, string> tagValueMap) { opc = new MyOPCItem(); foreach (var item in tagValueMap) { opc.key = item.Key; opc.Value = item.Value; return opc; } return null; } //public void ShowMessage(string str) //{ // //wsc.Send(JsonConvert.SerializeObject(str)); // // wsc.Send(str); // richTextBox1.AppendText(str + System.Environment.NewLine); //} /// <summary> /// websocket傳遞數據,和測試客戶端顯示。 /// </summary> /// <param name="opc"></param> public void ShowMessage(MyOPCItem opc) { wsc.Send(JsonConvert.SerializeObject(opc)); richTextBox1.AppendText(opc.Value + System.Environment.NewLine); } #endregion private void Form1_Load_1(object sender, EventArgs e) { KepServerLoad(); } private void Form1_FormClosing_1(object sender, FormClosingEventArgs e) { KepServer.Disconnect(); } } }
3.結論性能優化
初步實現與websocket的數據對接,以json對象的形式傳遞,還須要websocket服務端將其反序列化爲json字符串,並解析給前端使用。固然,這只是一個初步的Demo,其性能優化,線程佔有的內存,以及穩定性都有待測試。服務器