C#對於處理window操作系統下的設備有天然的優勢,對於大多數設備讀寫等操作來說基本上夠了,這裡只討論通過普通的大多數的設備的操作。涉及到兩大類SerialPort類,Socket的一些操作。不一定好,但希望分享出去,讓更多的人受益。。
由於設備的讀寫方式不同,串口,網口,usb,等各種各樣不同的方式,所以對外的操作,可能就達不到統一,沒法集中處理,造成很大程度代碼冗余,會給維護帶來很大不便。需要一個父類來對不同操作進行統一的一個約束,同時可以對外有一個統一的j接口,方便業務上邊的一些處理。
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace EquipmentOption { public abstract class Equipment { /// <summary> /// 讀取到的Code /// </summary> public string Code; /// <summary> /// 錯誤消息 /// </summary> public string Error = string.Empty; public BaseEquipment EquipmentModel; public int ReadTimeOut=500; public Equipment(BaseEquipment Model) { this.EquipmentModel = Model; } /// <summary> /// 掃描事件 /// </summary> private int scanning; public int Scanning { get { return this.scanning; } set { this.scanning = value; EquipmentArgs e = new EquipmentArgs(this.Code, this.Error); OnSetVelues(e); } } public event SetEventHandler SetEvent; public delegate void SetEventHandler(object sender, EquipmentArgs e); public class EquipmentArgs : EventArgs { public string Code; public string Error; public EquipmentArgs(string SnCode,string error) { this.Code = SnCode; this.Error = error; } } public void OnSetVelues(EquipmentArgs e) { if (this.SetEvent != null) { this.SetEvent(this, e); } } /// <summary> /// 檢測設備 /// </summary> /// <param name="message">錯誤消息返回值,僅當返回false才有值</param> /// <returns></returns> public abstract bool test(out string message); /// <summary> /// 給設備發送指令 /// </summary> /// <param name="command">指令內容</param> /// <param name="type">指令類型</param> /// <returns></returns> public abstract string SendMessage(String command, CommandType type); } }View Code
父類裡邊主要定義了一些公用的屬性,以及一個簡單的事件轉發。這個事件轉發用於統一網口設備和串口設備的獲取數據方式
調用方式如下:
private void Form1_Load(object sender, EventArgs e) { Equipment Comquip = new ComEquipment(new BaseEquipment()); Comquip.SetEvent += Equipment_GetCodeEvent; Equipment IPEquip = new IPEquipment(new BaseEquipment()); IPEquip.SetEvent += Equipment_GetCodeEvent; } void Equipment_GetCodeEvent(object sender, Equipment.EquipmentArgs e) { string code = e.Code;//這裡的Code就是從設備中讀取到的值 }
可以把需要用到的基礎消息丟到baseEquipment中用來初始化對應的設備,然後,把對於設備讀取到的信息就是這裡的e.code。不管網口串口都是一樣的返回.
設備的操作無非讀寫
對於用串口連接的設備:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO.Ports; using System.Threading; namespace EquipmentOption { public class ComEquipment : Equipment { private SerialPort Port; public ComEquipment(BaseEquipment baseModel) : base(baseModel) { this.Port = new SerialPort(baseModel.Port); Port.BaudRate = baseModel.BaudRate; Port.StopBits = (StopBits)baseModel.StopBit; Port.Parity = (Parity)baseModel.ParityCheck; this.Port.DataReceived += Port_DataReceived; } //事件轉發 void Port_DataReceived(object sender, SerialDataReceivedEventArgs e) { Thread.Sleep(this.EquipmentModel.SleepTime); this.Error = string.Empty; this.Code = string.Empty; try { switch (this.EquipmentModel.ReadType) { case 1: this.Code = (sender as SerialPort).ReadLine(); break; case 2: this.Code = (sender as SerialPort).ReadExisting(); break; default: Error = string.Concat(this.EquipmentModel.EquipmentName, "讀取有誤"); break; } ++this.Scanning;//這裡切記是屬性值變化才會觸發事件 } catch { Error = string.Concat(this.EquipmentModel.EquipmentName, "配置錯誤,請調整"); } } /// <summary> /// 檢測 /// </summary> /// <param name="message"></param> /// <returns></returns> public override bool test(out string message) { message = ""; bool result = false; if (this.Port != null) { try { Port.Open(); result = true; } catch { message = string.Concat("設備", this.EquipmentModel.EquipmentName, "異常"); result = false; } finally { if (Port.IsOpen) { Port.Close(); } } } else { message = string.Concat("設備", this.EquipmentModel.EquipmentName, "初始化失敗"); result = false; } return result; } /// <summary> /// 發送命令 /// </summary> /// <param name="command">命令</param> public override string SendMessage(String command, CommandType type) { if (!String.IsNullOrEmpty(command) && this.Port.IsOpen) { switch (type) { case CommandType.GetBytes: Byte[] commandsGetBytes = CommandConvert.CommandByGetBytes(command); this.Port.Write(commandsGetBytes, 0, commandsGetBytes.Length); break; case CommandType.Command16: Byte[] commands16 = CommandConvert.CommandFrom16(command); this.Port.Write(commands16, 0, commands16.Length); break; case CommandType.Command10: Byte[] commands10 = CommandConvert.CommandFrom10(command); this.Port.Write(commands10, 0, commands10.Length); break; case CommandType.CommandText: this.Port.Write(command); break; } return this.Port.PortName + "發送數據:" + command; } else { return "串口" + this.Port.PortName + "未打開"; } } } }View Code
對於用網口連接的設備:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net; using System.Net.Sockets; using System.Threading; namespace EquipmentOption { public class IPEquipment : Equipment { private IPEndPoint IPPort; private IPAddress IP; public IPEquipment(BaseEquipment baseModel) : base(baseModel) { int Port = 0; if (int.TryParse(baseModel.Port, out Port)) { this.IP = IPAddress.Parse(baseModel.IPAddress); this.IPPort = new IPEndPoint(IP, Port); Thread t = new Thread(new ParameterizedThreadStart(ScanEvent)); t.Start(IPPort); } } public override bool test(out string message) { bool result = false; message = ""; Socket c = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // 創建Socket try { c.SendTimeout = 5000; c.Connect(IPPort); //連接到服務器 result = true; } catch { message =string.Concat("設備" , this.EquipmentModel.EquipmentName , "異常"); result = false; } finally { c.Close(); } return result; } public void ScanEvent(object ipe) { while (true) { try { //創建Socket並連接到服務器 Socket c = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // 創建Socket c.Connect((IPEndPoint)ipe); //連接到服務器 //接受從服務器返回的信息 byte[] recvBytes = new byte[1024]; int bytes; //bytes = c.Receive(recvBytes, recvBytes.Length, 0); //從服務器端接受返回信息 bytes = c.Receive(recvBytes); string Code = Encoding.Default.GetString(recvBytes, 0, bytes); Code = Code.Replace(EquipmentModel.Suffix, ""); this.Code = Code; c.Close(); ++this.Scanning; } catch(Exception ex) { Error = ex.ToString(); continue; } } } public override string SendMessage(string command, CommandType type) { //new mothed to SendMessage; return ""; } } }View Code
對於擴展而言,需要做的僅僅是不同類別的設備再增加不同的子類去繼承抽象類.