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
對於擴展而言,需要做的僅僅是不同類別的設備再增加不同的子類去繼承抽象類.