应用系统端口的统一设计(一)
本设计不通用,只针对特定的一类问题。
如果系统经常和多种端口打交道,例如:COM,TCP,UDP,短信,打印机等等外接端口通讯,那么可以这样设计。
每种通讯方式都是类似,连接,打开端口,接收和发送数据,解析数据给系统。
所以可以统一起来进行设计,这样扩充端口更加容易。
使用C#语言描述
public delegate void GameEventDelegate(object sender, Action action);// public class Action : EventArgs { public PlayPort Receiver = PlayPort.Logic; public Action(PlayPort sender, ICommand command) { Sender = sender; Receiver = PlayPort.Logic; Command = command; } public Action(PlayPort sender, PlayPort receiver, ICommand command) { Sender = sender; Receiver = receiver; Command = command; } public PlayPort Sender { get; set; } public ICommand Command { get; set; } }//端口服务接口 public interface IPortService { event GameEventDelegate OnPort; void Write(Action action); } public class ControlPanelPort : IPortService { private static ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private ConfigManager config; private ControlPanelExecutor executor = new ControlPanelExecutor(); ControlPanelPortQueueManager controlPanelPortQueueManager = new ControlPanelPortQueueManager(); private IPersistService persistService; public event EventHandler DataArrived; public IDataParser Parser { set { controlPanelPortQueueManager.Parser = value; controlPanelPortQueueManager.Start(); } } public Queue<byte[]> DataQueue = new Queue<byte[]>(); public ControlPanelPort(IPersistService persistService) { this.persistService = persistService; config = ConfigManager.Instance(persistService.LoadConfig()); Init(); } public SerialPort ControlPanelSerialPort { get; set; } #region IPortService Members public event GameEventDelegate OnPort; /// <summary> /// action中的data格式必须为int[] /// </summary> /// <param name="action"></param> public void Write(Action action) { try { if (action.Receiver != PlayPort.ControlPanel) return; if (ControlPanelSerialPort != null && ControlPanelSerialPort.IsOpen) executor.Execute(this, action); } catch (IOException ex) { log.Error(ex.Message,ex); if(ControlPanelSerialPort!=null) ControlPanelSerialPort.Close(); } } #endregion // private void Init() { try { ControlPanelSerialPort = new SerialPort("control panel"); ControlPanelSerialPort.PortName = config[ConfigKey.控制面板串口]; ControlPanelSerialPort.BaudRate = 57600; ControlPanelSerialPort.Handshake = Handshake.None; ControlPanelSerialPort.DataBits = 8; ControlPanelSerialPort.StopBits = StopBits.One; ControlPanelSerialPort.Parity = Parity.None; ControlPanelSerialPort.ReceivedBytesThreshold = 2; ControlPanelSerialPort.WriteTimeout = SerialPort.InfiniteTimeout; ControlPanelSerialPort.ReadTimeout = SerialPort.InfiniteTimeout; ControlPanelSerialPort.DataReceived += controlPanelPort_DataReceived; ControlPanelSerialPort.Open(); ControlPanelSerialPort.DiscardInBuffer(); ControlPanelSerialPort.DiscardOutBuffer(); // controlPanelPortQueueManager.ControlPort = this; } catch (Exception ex) { log.Error("控制面板端口初始化失败!" + ex.Message); } } private void controlPanelPort_DataReceived(object sender, SerialDataReceivedEventArgs e) { try { if (OnPort != null) { if (ControlPanelSerialPort == null) return; Application.DoEvents(); Thread.Sleep(50); byte[] data = new byte[ControlPanelSerialPort.BytesToRead]; ControlPanelSerialPort.Read(data, 0, data.Length); log.Warn("<<<<接收控制面板信息,length:" + data.Length); DataQueue.Enqueue(data); if (DataArrived != null) { DataArrived(this, null); } } } catch (Exception ex) { log.Error(ex.Message, ex); } } public void FireOnPort(Action action) { if(OnPort!=null) { OnPort(this, action); } } } public class PortProxy : IPortService { private static ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private IPortService communicationPortService1; private IPortService monitorPortService; private IPortService controlPanelPortService1; private IPortService printPortService1; private IPortService tcpPortService1; private IPortService sMSPortService; public IPortService CommunicationPortService { set { communicationPortService1 = value; communicationPortService1.OnPort += Event_OnPort; } } public IPortService MonitorPortService { set { monitorPortService = value; monitorPortService.OnPort += Event_OnPort; } } public IPortService PrintPortService { set { printPortService1 = value; printPortService1.OnPort += Event_OnPort; } } public IPortService ControlPanelPortService { set { controlPanelPortService1 = value; controlPanelPortService1.OnPort += Event_OnPort; } } public IPortService TcpPortService { set { tcpPortService1 = value; tcpPortService1.OnPort += Event_OnPort; } } public IPortService SMSPortService { set { sMSPortService = value; sMSPortService.OnPort += Event_OnPort; } } #region IPortService Members public event GameEventDelegate OnPort; public void Write(Action action) { switch (action.Receiver) { case PlayPort.ControlPanel: { controlPanelPortService1.Write(action); } break; case PlayPort.Printer: { printPortService1.Write(action); } break; case PlayPort.Udp: { communicationPortService1.Write(action); } break; case PlayPort.Tcp: { tcpPortService1.Write(action); } break; case PlayPort.SMS: { sMSPortService.Write(action); } break; case PlayPort.Monitor: { monitorPortService.Write(action); } break; default: Event_OnPort(this, action); break; } } #endregion private void Event_OnPort(object sender, Action action) { if (OnPort != null) OnPort(sender, action); } } public abstract class AbstractGameState : IGameState { protected IPortService logic; // protected const PlayPort LOGIC_PORT = PlayPort.Logic; protected const PlayPort CONTROL_PANEL_PORT = PlayPort.ControlPanel; protected const PlayPort PRINTER_PORT = PlayPort.Printer; protected const PlayPort SMS_PORT = PlayPort.SMS; protected const PlayPort UDP_PORT = PlayPort.Udp; #region IGameState Members public IPortService PortService { set { logic = value; logic.OnPort += Logic_OnPortEvent; } get { return logic; } } protected abstract void Logic_OnPortEvent(object sender, Action action); }SingleCommand command = SingleCommand.Instance[CommandCode.指令]; command.Data = printParams; logic.Write(new Action(PlayPort.Logic, PlayPort.Printer, command));
public abstract class AbstractSingleGameState:AbstractGameState { protected override void Logic_OnPortEvent(object sender, Action action) { // if(GameContext.GameState==null) return; if (GameContext.GameState.CurrentState == CurrentState) { try { ActionChainNode stateListener = ActionLockStateManager.Instance; if (stateListener.Process(this, action)) return; ThreadPool.QueueUserWorkItem(new WaitCallback(Doo),action); OnPortEvent(sender, action); } catch (Exception ex) { log.Error(ex.Message,ex); } } } private static ActionChainNode globalChain = GlobalActionChainFactory.GetChain(); protected void Doo(object state) { //将不是立即执行的命令填出gamestate栈中,等到actionFilterChain的调用 ActionChainNode stackChain = GlobalActionStackFactory.GetChain(); stackChain.Process(this, (Action) state); // globalChain.Process(this, (Action)state); } protected virtual void OnPortEvent(object sender, Action action) { } } public class StepWaitingState : AbstractSingleGameState { public override GameState CurrentState { get { return GameState.StepWaiting; } } public StepWaitingState() { } public override object Enter(Action action) { } protected override void OnPortEvent(object sender, Action action) { Doo(action); } private void Doo(object state) { Action action = (Action) state; ActionChainNode controlPanelActionChain = WatingActionChainFactory.GetChain(); controlPanelActionChain.Process(this, action); } public override IGameState Transit(Action action) { if (GameContext.GameState.CurrentState == CurrentState) GameContext.SetState(StateFactory.StepPost, action); return GameContext.GameState; } }<object id="PortProxy" type="Single.Core.PortProxy,Single.Core"><property name="CommunicationPortService" ref="UdpPort"/><property name="PrintPortService" ref="PrintPort"/><property name="ControlPanelPortService" ref="ControlPanelPort"/><property name="TcpPortService" ref="TcpPort"/><property name="SMSPortService" ref="SMSPort"/><property name="MonitorPortService" ref="UdpMonitorPort"/></object>
<object id="AbstractStateBase" abstract="true"><property name="PortService" ref="PortProxy"/><property name="PersistService" ref="SinglePersistService"/></object>