C#对于处理window操作系统下的设备有天然的优势,对于大多数设备读写等操作来说基本上够了,这里只讨论通过普通的大多数的设备的操作。涉及到两大类SerialPort类,Socket的一些操作。不一定好,但希望分享出去,让更多的人受益。。
由于设备的读写方式不同,串口,网口,usb,等各种各样不同的方式,所以对外的操作,可能就达不到统一,没法集中处理,造成很大程度代码冗余,会给维护带来很大不便。需要一个父类来对不同操作进行统一的一个约束,同时可以对外有一个统一的j接口,方便业务上边的一些处理。
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace EquipmentOption 7 { 8 public abstract class Equipment 9 { 10 11 /// <summary> 12 /// 读取到的Code 13 /// </summary> 14 public string Code; 15 /// <summary> 16 /// 错误消息 17 /// </summary> 18 public string Error = string.Empty; 19 public BaseEquipment EquipmentModel; 20 21 public int ReadTimeOut=500; 22 public Equipment(BaseEquipment Model) 23 { 24 this.EquipmentModel = Model; 25 } 26 /// <summary> 27 /// 扫描事件 28 /// </summary> 29 private int scanning; 30 public int Scanning 31 { 32 get 33 { 34 return this.scanning; 35 } 36 set 37 { 38 this.scanning = value; 39 EquipmentArgs e = new EquipmentArgs(this.Code, this.Error); 40 OnSetVelues(e); 41 } 42 } 43 public event SetEventHandler SetEvent; 44 public delegate void SetEventHandler(object sender, EquipmentArgs e); 45 public class EquipmentArgs : EventArgs 46 { 47 public string Code; 48 public string Error; 49 public EquipmentArgs(string SnCode,string error) 50 { 51 this.Code = SnCode; 52 this.Error = error; 53 } 54 } 55 public void OnSetVelues(EquipmentArgs e) 56 { 57 if (this.SetEvent != null) 58 { 59 this.SetEvent(this, e); 60 } 61 } 62 /// <summary> 63 /// 检测设备 64 /// </summary> 65 /// <param name="message">错误消息返回值,仅当返回false才有值</param> 66 /// <returns></returns> 67 public abstract bool test(out string message); 68 /// <summary> 69 /// 给设备发送指令 70 /// </summary> 71 /// <param name="command">指令内容</param> 72 /// <param name="type">指令类型</param> 73 /// <returns></returns> 74 public abstract string SendMessage(String command, CommandType type); 75 } 76 77 }
父类里边主要定义了一些公用的属性,以及一个简单的事件转发。这个事件转发用于统一网口设备和串口设备的获取数据方式
调用方式如下:
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。不管网口串口都是一样的返回.
设备的操作无非读写
对于用串口连接的设备:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.IO.Ports; 6 using System.Threading; 7 namespace EquipmentOption 8 { 9 public class ComEquipment : Equipment 10 { 11 private SerialPort Port; 12 public ComEquipment(BaseEquipment baseModel) : 13 base(baseModel) 14 { 15 this.Port = new SerialPort(baseModel.Port); 16 Port.BaudRate = baseModel.BaudRate; 17 Port.StopBits = (StopBits)baseModel.StopBit; 18 Port.Parity = (Parity)baseModel.ParityCheck; 19 this.Port.DataReceived += Port_DataReceived; 20 } 21 //事件转发 22 void Port_DataReceived(object sender, SerialDataReceivedEventArgs e) 23 { 24 Thread.Sleep(this.EquipmentModel.SleepTime); 25 this.Error = string.Empty; 26 this.Code = string.Empty; 27 try 28 { 29 switch (this.EquipmentModel.ReadType) 30 { 31 case 1: 32 this.Code = (sender as SerialPort).ReadLine(); 33 break; 34 case 2: 35 this.Code = (sender as SerialPort).ReadExisting(); 36 break; 37 default: 38 Error = string.Concat(this.EquipmentModel.EquipmentName, "读取有误"); 39 break; 40 } 41 ++this.Scanning;//这里切记是属性值变化才会触发事件 42 43 } 44 catch 45 { 46 Error = string.Concat(this.EquipmentModel.EquipmentName, "配置错误,请调整"); 47 } 48 } 49 50 /// <summary> 51 /// 检测 52 /// </summary> 53 /// <param name="message"></param> 54 /// <returns></returns> 55 public override bool test(out string message) 56 { 57 message = ""; 58 bool result = false; 59 if (this.Port != null) 60 { 61 try 62 { 63 Port.Open(); 64 result = true; 65 } 66 catch 67 { 68 message = string.Concat("设备", this.EquipmentModel.EquipmentName, "异常"); 69 result = false; 70 } 71 finally 72 { 73 if (Port.IsOpen) 74 { 75 Port.Close(); 76 } 77 } 78 } 79 else 80 { 81 message = string.Concat("设备", this.EquipmentModel.EquipmentName, "初始化失败"); 82 result = false; 83 } 84 return result; 85 } 86 /// <summary> 87 /// 发送命令 88 /// </summary> 89 /// <param name="command">命令</param> 90 public override string SendMessage(String command, CommandType type) 91 { 92 if (!String.IsNullOrEmpty(command) && this.Port.IsOpen) 93 { 94 switch (type) 95 { 96 case CommandType.GetBytes: 97 Byte[] commandsGetBytes = CommandConvert.CommandByGetBytes(command); 98 this.Port.Write(commandsGetBytes, 0, commandsGetBytes.Length); 99 break; 100 case CommandType.Command16: 101 Byte[] commands16 = CommandConvert.CommandFrom16(command); 102 this.Port.Write(commands16, 0, commands16.Length); 103 break; 104 case CommandType.Command10: 105 Byte[] commands10 = CommandConvert.CommandFrom10(command); 106 this.Port.Write(commands10, 0, commands10.Length); 107 break; 108 case CommandType.CommandText: 109 this.Port.Write(command); 110 break; 111 } 112 return this.Port.PortName + "发送数据:" + command; 113 } 114 else 115 { 116 return "串口" + this.Port.PortName + "未打开"; 117 } 118 } 119 } 120 }
对于用网口连接的设备:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Net; 6 using System.Net.Sockets; 7 using System.Threading; 8 9 namespace EquipmentOption 10 { 11 public class IPEquipment : Equipment 12 { 13 private IPEndPoint IPPort; 14 private IPAddress IP; 15 public IPEquipment(BaseEquipment baseModel) : 16 base(baseModel) 17 { 18 int Port = 0; 19 if (int.TryParse(baseModel.Port, out Port)) 20 { 21 this.IP = IPAddress.Parse(baseModel.IPAddress); 22 this.IPPort = new IPEndPoint(IP, Port); 23 Thread t = new Thread(new ParameterizedThreadStart(ScanEvent)); 24 t.Start(IPPort); 25 } 26 } 27 28 public override bool test(out string message) 29 { 30 bool result = false; message = ""; 31 Socket c = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // 创建Socket 32 try 33 { 34 c.SendTimeout = 5000; 35 c.Connect(IPPort); //连接到服务器 36 result = true; 37 } 38 catch 39 { 40 message =string.Concat("设备" , this.EquipmentModel.EquipmentName , "异常"); 41 result = false; 42 } 43 finally 44 { 45 c.Close(); 46 } 47 return result; 48 } 49 public void ScanEvent(object ipe) 50 { 51 while (true) 52 { 53 try 54 { 55 //创建Socket并连接到服务器 56 Socket c = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // 创建Socket 57 c.Connect((IPEndPoint)ipe); //连接到服务器 58 //接受从服务器返回的信息 59 byte[] recvBytes = new byte[1024]; 60 int bytes; 61 //bytes = c.Receive(recvBytes, recvBytes.Length, 0); //从服务器端接受返回信息 62 bytes = c.Receive(recvBytes); 63 string Code = Encoding.Default.GetString(recvBytes, 0, bytes); 64 Code = Code.Replace(EquipmentModel.Suffix, ""); 65 this.Code = Code; 66 c.Close(); 67 ++this.Scanning; 68 } 69 catch(Exception ex) 70 { 71 Error = ex.ToString(); 72 continue; 73 } 74 } 75 } 76 77 public override string SendMessage(string command, CommandType type) 78 { 79 //new mothed to SendMessage; 80 return ""; 81 } 82 } 83 }
对于扩展而言,需要做的仅仅是不同类别的设备再增加不同的子类去继承抽象类.