`
qixin000
  • 浏览: 20890 次
  • 性别: Icon_minigender_1
  • 来自: 黑龙江
文章分类
社区版块
存档分类
最新评论

应用系统端口的统一设计(一)

阅读更多
本设计不通用,只针对特定的一类问题。
如果系统经常和多种端口打交道,例如: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);
    }


Write函数:向设备写入数据
OnPort事件接收数据,并通知系统接收数据
Java代码和上面类似!

扩展接口可以这样
 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);
            }
        }
    }

其他所有的端口扩展都是类似的
在接受端口数据后,将数据直接放到处理队列里面,不要直接将处理代码放到这里,否则影响端口的继续工作,接收数据。不可以认为数据一次性都直接收完毕,数据可能是多次才能接受完成,所以处理的时候都要将数据放到队列里面,然后通过另一个线程处理。

数据接收函数
controlPanelPort_DataReceived
将数据放到队列中
DataQueue.Enqueue(data);
处理完毕后,触发事件,通知订阅者
OnPort(this, action);

Write数据到端口的执行者:ControlPanelExecutor
处理队列数据的管理者:ControlPanelPortQueueManager
持久化服务:IPersistService

其他端口都是类似处理!!!
下面将所有端口统一起来
public class PortProxy : IPortService
PortProxy类型是向前端表露的统一端口代理
他统一了所有端口的访问方式,这里使用了Proxy模式
 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);
        }
    }


他代理了所有的端口,另外值得说明的是他充当了一个逻辑接口,该接口是一个虚拟的系统之间通信的接口,并不代表一个实际存在的接口,该接口的存在大大减少了系统模块之间的耦合性
应用的时候通过注入将可以将Port实例注入了
 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);
    }

这里面的logic即使端口,他代表了所有的端口服务,通过它可以访问所有的端口,端口服务的客户访问大大简化,也与所有的具体端口松耦合,维护上大为简化

访问方法:
 SingleCommand command = SingleCommand.Instance[CommandCode.指令];
 command.Data = printParams;
 logic.Write(new Action(PlayPort.Logic, PlayPort.Printer, command));

表示逻辑端口想打印机发送指令,进行打印
数据接收会触发OnPort事件
客户可以通过该事件进行程序处理
 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)
        {
        }
    }

程序通过Logic_OnPortEvent处理程序进行接受指令的处理
这里使用了职责链模式进行所有的指令处理,下一节将写出该模式的设计

该处理函数既可以处理全局指令,也可以处理当前状态指令,并将事件进行传递。
传递到具体的处理类
    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;
        }
    }


如果接受的指令数据传递到当前状态后,通过该状态的职责链进行处理
ActionChainNode controlPanelActionChain = WatingActionChainFactory.GetChain();

整体就是这样了!

端口代理的实例化
	<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>


PortProxy的注入
<object id="AbstractStateBase" abstract="true">
	<property name="PortService" ref="PortProxy"/>
	<property name="PersistService" ref="SinglePersistService"/>
</object>


综上,这样设计之后,客户在使用的过程中所有的细节都没有接触,只是统一通过PortProxy进行通信,所有的端口扩展也都通过ProtProxy进行扩充,不影响客户使用,扩展也更容易,端口的扩展继承统一的PortService,扩展方式统一!

原始链接
http://qixin000.iteye.com/blog/1425135
0
0
分享到:
评论

相关推荐

    信息系统安全设计方案及对策模板.doc

    XX公司 ××项目 安全设计方案 (模板) &lt;备注:模板中斜体部分用于指导用户填写容,在采用该模板完成交付物时,需要删 除所有斜体容&gt; XX公司 二〇一X年X月 批 准: 审 核: 校 核: 编 写: 版本记录 "版本编号...

    计算机网络系统设计项目方案.doc

    计算机网络系统设计项目方案 概述 1 设计依据 相关专业的设计应符合国家现行设计规,并参考地方相应规包括: 《博达国际公共服务大厦楼宇智能系统设计与总包工程招标文件》 中华人民国建设部《智能建筑设计标准》 ...

    短信平台设计方案.pdf

    二、平台总体规划 2.1、平台总体设计 根据短信平台建设的总体要求,结合目前应用系统状况,系统建设的 技术路线应坚持"需求为导向、应用促发展,统筹规划、科技支撑,分 工负责、持续发展"的指导思想,建立安全与...

    机场内通系统的设计方案.doc

    4) 旅客求助系统既在机场的各个公共场所设置求助终端和在机场设立一个旅客求助呼叫中 心,每个需要帮助的旅客可在任意一个求助终端处得到呼叫中心统一高质量的语音服务 。 5) 内通系统主要由内通服务器或主机、用户...

    基于89C51单片机的秒表课程设计.doc

    1 课程设计的目的 《单片机应用基础》课程设计是学好本门课程的又一重要实践性教学环节,课程设计的 目的就是配合本课程的教学和平时实验,以达到巩固消化课程的内容,进一步加强综合 应用能力及单片机应用系统开发...

    89C51单片机课程设计之秒表设计实验报告.doc

    课程设计的目的和任务 1.1单片机秒表课程设计的概述 一、课程设计题目 秒表系统设计——用STC89C51设计一个4位LED数码显示"秒表",显示时间为000.0~9分 59.9秒,每10毫秒自动加一,每1000毫秒自动加一秒。...

    飞管1394总线接口模块设计实现

    在面向新一代飞机管理系统的1394总线应用中,为满足节点标准化设计,提高电气特性信号质量,降低节点的维护成本,提出了一种基于1394总线协议的飞管1394总线接口模块。该模块具有功耗低、体积小、重量轻、可靠性高的...

    基于数据库管理的数据采集系统的设计及实现.docx

    鉴于此,本文主要针对以数据库的管理为基础下数据采集的系统设计与实现进行综述分析,望能够为相关专家及学者对这一课题的深入研究提供有价值的参考或者依据。 1、系统总体架构 针对数据的采集系统,选择硬件方面...

    汉光 电力监控系统在企业供配电系统中的应用 .pdf

    主站由就地连网服务器组成,并有固定IP和80端口,实现多个客户端多用户可以同时访问电力监控系统网络。 分布式云平台Web网络架构: 主站由云端网络服务器+数据库服务器组成,现场设备数据通过通信管理机、4G网关、...

    什么是VLAN

    新出台的标准进一步完善了VLAN的体系结构,统一了Frame-Tagging方式中不同厂商的标签格式,并制定了VLAN标准在未来一段时间内的发展方向,形成的802.1Q的标准在业界获得了广泛的推广。它成为VLAN史上的一块里程碑。...

    网吧管理系统数据库设计报告.doc

    文档介绍 1.1文档目的 网吧管理系统软件设计文档的重要组成部分,本文档主要对该软件后台数据库的概 念模型设计和物理模型设计作出了统一的规定,同时还确定了每个表的数据结构。它 是开发人员重要参考依据。 1.2...

    基于89C51单片机的秒表课程设计(2).doc

    提供编程所需要的计算机一台 要求完成的主要任务:(包括课程设计工作量及其技术要求,以及说明书撰写等具体要 求) 1、用定时器/计数器设计一个简单的秒表,能显示计时状态和结果。 2、进行电路实验或仿真,并使用...

    时间同步服务器技术规范书.pdf

    为计算机网络、计算 机应用系统、流程控制管理系统、电子商务系统、网上 B2B 系统以及数据库的保存及维护需 要提供精密的标准时间信号和时间戳服务。 SNTM 系列网络时间服务器作为思利敏电力公司系列时间产品单元,...

    XX办公楼综合网络布线设计方案.doc

    经济性:统一考虑闭路电视系统、网络系统、通信系统和视频点播系统,统一设计,统 一施工,统一管理。避免重复劳动和设备占用。 可维护性:系统设计应科学合理,做到维护简单、方便。故障影响范围尽可能小。 1.3 ...

    经管学院网络系统规划设计网络综合布线

    在企业信息化建设过程中,网络综合布线是非常关键的一个环节,根据我院经管分院的信息化建设项目的要求,网络建设布线必须按照设计标准(SP-2840国际综合布线标准,EIA/TIA569电信服务商业布线标准)进行,达到1000M...

    局域网设计方案-可靠安全实验室设计.doc

    如果端口是access端口,则把端口加入到另外一个vlan的同时,系统自动把该端口从原 来的vlan中删除掉; 3. 除了VLAN1,如果VLAN XX不存在,在系统视图下键入VLAN XX,则创建VLAN XX并进入VLAN视图;如果VLAN XX已经...

    校园视频监控设计方案.docx

    该系统的设计采用数字视频方式,前端数字摄像机通过IP端口直接与交换机连接,通过监控网络传输到学校监控中心,监控中心对所有图像进行集中管理,这一技术路线保证了系统具有良好的清晰度、较少的服务器资源占用、...

    校园视频监控设计方案.doc

    该系统的设计采用数字视频方式,前端数字摄像机通过IP端口直接与交换机连接,通 过监控网络传输到学校监控中心,监控中心对所有图像进行集中管理,这一技术路线保 证了系统具有良好的清晰度、较少的服务器资源占用...

    毕业设计-小型网吧局域网设计.doc

    在管理信息系统、科研设计等领域的广泛应用,为网络平台的设计提出了更高的要求。 为了更好地满足用户的需求,保证系统能正常稳定运行,在较长的时间内不落后,在本 网络系统方案设计中,我们认为应当把握以下几个...

    计算机教室工程设计方案.doc

    当增加新的应用系统, 或增加新的小型机系统、系统升级、系统扩容、远程网络互联时,具备方便的扩 展适应性。为此,必须遵循开放性的原则,尽量采用标准化设备和技术,采用标 准的、开放的软、硬件,尽量采用标准化...

Global site tag (gtag.js) - Google Analytics