.net下的面向工控领域的远程方法调用(RMI)中间件,通信层实现

在协议栈实现的基础上,如何将封包后字节流发送到远端设备,或从远端设备接收封包的字节流,则需要通信层辅助实现,通信层负责连接构建、监听、会话管理等,是在远程方法调用,代码编写的最底一层,其中连接的管理、数据调度的分离等,一直是底层通信服务端开发人员在不断解决的问题,要做到更多的性能优化,比如异步IO、重叠IO、IO完成端口等,每一种方式无不是在尽可能提高通信的效率,增大并发的连接数,会话的稳定等。

在工控中应用,尤其是对设备监控时,大多数设备是作为服务端,提供对外服务的通信端口,远端应用连接到设备监听端口上,监听设备数据,由于工业网络环境,电磁干扰复杂,会造成设备在通信连接中,可能构建的连接通道,在设备端被自行拆解,由于网络路由等,路由表中的映射缓存,并未对应的拆除,应用端可能认为连接还是正常,会造成设备数据无法接收和监控到。因此区别于,互联网应用中的业务需求,在工控网络中,应用端如何保证连接的高可靠、稳定、实时性等,就是在构建通信中第一考虑的要素。

此处的RMI组件,不同于互联网应用中的RMI组件,也在底层通信环节要求能实现双向监听的同时,能自动有心跳检测机制,在通信空闲时,自动检测掉线或连接被拆除等情况。

为了减少与应用层的关联性,在设计通信部分中间件时,严格的按照设计模式,进行与业务层的隔离,最终拆分到几个基本的输入、输出类中,包括:请求结构数据、请求输入消息处理器、应答结构数据、应答输出消息处理器,设计的思路是,所有的发送,都可以转化成统一的结构化数据,采用何种方式进行消息的封包处理,是由重写请求输入消息处理器的派生类实现,这样请求端,就不需要关心各种发送的同步、调度等相关的通信环节的事物,而接收端,同样由两个基类辅助实现,由应答数据结构和应答输出消息处理器辅助实现,具体的应答消息处理,同样是由应答输出消息处理器的派生类辅助实现,这样所有的应答,都会自动转化成统一的结构化数据。最终实现的目的是,通信发送、接收和最负杂的连接、会话等管理,全部由通信层接管实现了,调用组件时,需要关心的消息封包等,也通过派生注入方式,自动暴露给调用者,调用者可以自由处理,其最关心的消息处理部分。

通信层由公共通信接口定义:

/// <summary>
    /// 通信接口
    /// </summary>
    /// <typeparam name="TRequest">请求数据类型</typeparam>
    /// <typeparam name="TResponse">应答数据类型</typeparam>
    public interface ICommunication<TRequest,TResponse> 
        where TRequest:BaseRequestData 
        where TResponse : BaseResponseData
    {
        /// <summary>
        /// 启动
        /// 如果打开失败,会自动尝试关闭掉
        /// </summary>
        void Open();
        /// <summary>
        /// 是否开启
        /// </summary>
        bool IsOpen { get; }
        /// <summary>
        /// 请求发送
        /// 不建议与异步请求交错调用,会引起线程冲突
        /// </summary>
        /// <param name="request">请求发送的数据</param>
        bool Request(TRequest request);
        /// <summary>
        /// 异步请求数据,在其他线程上
        /// 不建议与同步请求交错调用,会引起线程冲突
        /// </summary>
        /// <param name="request">请求发送的数据</param>
        /// <param name="ex">处理异常信息</param>
        bool TryASyncRequest(TRequest request,out Exception ex);
        /// <summary>
        /// 请求数据,根据会话ID发送,
        /// 一般用于并发处理场合,根据ID来确认具体的发送会话,
        /// 用于服务监听应答场合
        /// 不建议与异步请求交错调用,会引起线程冲突
        /// </summary>
        /// <param name="sessionID">会话ID</param>
        /// <param name="request">请求发送的数据</param>
        bool Request(string sessionID,TRequest request);
        /// <summary>
        /// 广播数据,面向所有的连接,用于小连接数场合
        /// </summary>
        /// <param name="requestData">请求数据</param>
        void RequestBroadCast(TRequest requestData);
        /// <summary>
        /// 发送请求完成事件,同步到应答处理线程上,用于发送请求与应答请求,在应答线程上进行复合处理
        /// </summary>
        event RequestCompletedHandler<TRequest> OnRequestCompleted;
        /// <summary>
        /// 数据应答
        /// 异步线程上消息队列响应
        /// </summary>
        event ResponseHandler<TResponse> OnResponseBuffer;
        /// <summary>
        /// 异常信息响应
        /// 异步线程上消息队列响应
        /// </summary>
        event InfoHandler<ResponseInfo> OnResponseInfo;
        /// <summary>
        /// 操作状态
        /// </summary>
        event ResponseHandler<OperateStatus> OnOperateStaus;
        /// <summary>
        /// 会话构建后触发
        /// </summary>
        event SessionHandler OnSessionAdded;
        /// <summary>
        /// 会话从链表中移除后触发
        /// </summary>
        event SessionHandler OnSessionRemoved;
        /// <summary>
        /// 关闭
        /// </summary>
        void Close();
        /// <summary>
        /// 监听的地址和端口
        /// </summary>
        string EndPort { get; set; }
        /// <summary>
        /// 通信对象ID
        /// </summary>
        Guid CommunicationID { get;}
    }

其抽象类中,实现了大部分的通用部分的逻辑,包括对外的一些接口实现和应答处理等,抽象基类代码:

 /// <summary>
    /// 通信基类
    /// </summary>
    /// <typeparam name="TRequest">请求数据类型</typeparam>
    /// <typeparam name="TResponse">应答数据类型</typeparam>
    public abstract class BaseCommunication<TRequest,TResponse> 
        : ICommunication<TRequest,TResponse>
        where TRequest : BaseRequestData
        where TResponse : BaseResponseData
    {
        public BaseCommunication()
        {
            this.communicationID = Guid.NewGuid();
        }
        /// <summary>
        /// 异常时显示对应的设备名称信息
        /// </summary>
        protected string deviceInfo = null;
        /// <summary>
        /// 响应处理消息队列,用于应答排队
        /// </summary>
        private IMessageFIFO responseMessageFIFO = null;
        
        /// <summary>
        /// 是否正在关闭
        /// </summary>
        protected volatile bool onClosing = false;
        /// <summary>
        /// 启动
        /// 如果打开失败,会自动尝试关闭掉
        /// </summary>
        public abstract void Open();
        /// <summary>
        /// 是否开启
        /// </summary>
        public bool IsOpen
        {
            get
            {
                if (responseMessageFIFO == null)
                {
                    return false;
                }
                return responseMessageFIFO.IsOpened;
            }
        }
        /// <summary>
        /// 关闭
        /// </summary>
        public abstract void Close();
        #region 请求写入数据
        /// <summary>
        /// 请求发送的数据
        /// </summary>
        /// <param name="data">请求数据</param>
        public virtual bool Request(TRequest data)
        {
            throw new NotImplementedException(string.Format("{0}不支持Request的调用", this.GetType().FullName));
        }
        /// <summary>
        /// 请求数据,根据会话ID发送,
        /// 一般用于并发处理场合,根据ID来确认具体的发送会话,
        /// 用于服务监听应答场合
        /// </summary>
        /// <param name="sessionID">会话ID</param>
        /// <param name="request">请求发送的数据</param>
        public virtual bool Request(string sessionID, TRequest request)
        {
            throw new NotImplementedException(string.Format("{0}不支持Request的调用", this.GetType().FullName));
        }
        /// <summary>
        /// 异步请求数据,在其他线程上
        /// </summary>
        /// <param name="request">请求的数据</param>
        public virtual bool TryASyncRequest(TRequest request,out Exception ex)
        {
             ex=new Exception(string.Format("{0}不支持ASyncRequest的调用", this.GetType().FullName));
             return false;
        }
        /// <summary>
        /// 请求广播发送数据
        /// </summary>
        /// <param name="requestData">请求数据</param>
        public virtual void RequestBroadCast(TRequest requestData)
        {
            throw new NotImplementedException(string.Format("{0}不支持RequestBroadCast的调用", this.GetType().FullName));
        }
        #endregion
        /// <summary>
        /// 压入数据
        /// </summary>
        /// <param name="obj"></param>
        protected virtual void Post(object obj)
        {
            if (responseMessageFIFO != null && responseMessageFIFO.IsOpened == true)
            {
                responseMessageFIFO.Post(obj);
                return;
            }
            else if (obj is ResponseInfo)
            {
                this.FeedResponseInfo((ResponseInfo)obj);
            }
            else if (obj is TResponse)
            {
                FeedResponse((TResponse)obj);
            }
            else if (obj is SessionInfo)
            {
                FeedSessionInfo((SessionInfo)obj);
            }
            else if (obj is TRequest)
            {
                FeedRequestCompleted((TRequest)obj);
            }
            else
            {
                responseMessageFIFO_Exceute(obj);
            }
        }
        /// <summary>
        /// 回调处理数据
        /// </summary>
        /// <param name="obj"></param>
        protected virtual void responseMessageFIFO_Exceute(object obj)
        {
            if (obj is TResponse)
            {
                FeedResponse((TResponse)obj);
            }
            else if (obj is TRequest)
            {
                FeedRequestCompleted((TRequest)obj);
            }
            else if (obj is SessionInfo)
            {
                FeedSessionInfo((SessionInfo)obj);
            }
            else if (obj is ResponseInfo)
            {
                this.FeedResponseInfo((ResponseInfo)obj);
            }
        }
      
       /// <summary>
       /// 会话信息通知
       /// </summary>
       /// <param name="session"></param>
       protected void FeedSessionInfo(SessionInfo session)
       {
           if (session.OpenStatus == true)
           {
               if (OnSessionAdded != null)
               {
                   OnSessionAdded(session);
               }
           }
           else if (session.OpenStatus == false)
           {
               if (OnSessionRemoved != null)
               {
                   OnSessionRemoved(session);
               }
           }
       }
       /// <summary>
       /// 通知请求完成,同步到应答处理线程上
       /// </summary>
       /// <param name="request"></param>
       protected void FeedRequestCompleted(TRequest request)
       {
           if (OnRequestCompleted != null)
           {
               OnRequestCompleted(this, request);
           }
       }
       /// <summary>
       /// 通知应答
       /// </summary>
       /// <param name="response"></param>
       protected void FeedResponse(TResponse response)
       {
           if (OnResponseBuffer != null)
           {
               OnResponseBuffer(this, response);
           }
       }
       /// <summary>
       /// 通知消息
       /// </summary>
       /// <param name="responseInfo"></param>
       protected void FeedResponseInfo(ResponseInfo responseInfo)
       {
           if (OnResponseInfo != null)
           {
               OnResponseInfo(this, responseInfo);
           }
       }
       /// <summary>
       /// 响应消息队列启动
       /// </summary>
       protected virtual void OpenRespnoseMessageFIFO()
       {
           if (responseMessageFIFO == null)
           {
               responseMessageFIFO = MessageFIFOFactory.Create(MessageFIFOType.IOCPMessageFIFO);
               responseMessageFIFO.Excute += responseMessageFIFO_Exceute;
           }
           if (responseMessageFIFO != null && responseMessageFIFO.IsOpened == false)
           {
               responseMessageFIFO.Start();
           }
       }
        /// <summary>
        /// 响应消息队列关闭
        /// </summary>
        protected virtual void CloseResponseMessageFIFO()
        {
            if (responseMessageFIFO != null && responseMessageFIFO.IsOpened == true)
            {
                responseMessageFIFO.Stop();
            }
        }
        /// <summary>
        /// 获取心跳包参数
        /// </summary>
        /// <returns>
        /// 返回心跳包参数
        /// </returns>
        protected byte[] GetOptionValues(int heartRateTimeOut)
        {
            uint dummy = 0;
            byte[] inOptionValues = new byte[Marshal.SizeOf(dummy) * 3];
            BitConverter.GetBytes((uint)1).CopyTo(inOptionValues, 0);
            BitConverter.GetBytes((uint)heartRateTimeOut * 100).CopyTo(inOptionValues, Marshal.SizeOf(dummy));
            BitConverter.GetBytes((uint)heartRateTimeOut * 100).CopyTo(inOptionValues, Marshal.SizeOf(dummy) * 2);
            return inOptionValues;
        }
        /// <summary>
        /// 操作状态命令
        /// </summary>
        /// <param name="commandStatus">操作状态命令</param>
        protected virtual void FeedOperateStatus(OperateStatus operateStatus)
        {
            if (OnOperateStaus != null)
            {
                OnOperateStaus(this, operateStatus);
            }
        }
        /// <summary>
        /// 连接会话建立后触发
        /// </summary>
        /// <param name="sessionInfo">连接会话信息</param>
        protected virtual void RaiseConnectSession(SessionInfo sessionInfo)
        {
            sessionInfo.OpenStatus = true;
            this.Post(sessionInfo);
        }
        /// <summary>
        /// 连接会话移除后触发
        /// </summary>
        /// <param name="sessionInfo">连接会话信息</param>
        protected virtual void RemoveConnectSession(SessionInfo sessionInfo)
        {
            sessionInfo.OpenStatus = false;
            this.Post(sessionInfo);
        }
        /// <summary>
        /// 发送请求完成事件,同步到应答处理线程上
        /// </summary>
        public event RequestCompletedHandler<TRequest> OnRequestCompleted;
        /// <summary>
        /// 应答数据事件
        /// </summary>
        public event ResponseHandler<TResponse> OnResponseBuffer;
        /// <summary>
        /// 异常信息响应
        /// 异步线程上消息队列响应
        /// </summary>
        public event InfoHandler<ResponseInfo> OnResponseInfo;
        /// <summary>
        /// 操作状态
        /// </summary>
        public event ResponseHandler<OperateStatus> OnOperateStaus;
        /// <summary>
        /// 会话构建后触发
        /// </summary>
        public event SessionHandler OnSessionAdded;
        /// <summary>
        /// 会话从链表中移除后触发
        /// </summary>
        public event SessionHandler OnSessionRemoved;
        public string EndPort
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }
        /// <summary>
        /// 将字节数组转化成对应的字符串
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="send"></param>
        /// <returns></returns>
        protected string BytesToHexString(byte[] buffer,bool send)
        {
            if (buffer == null || buffer.Length == 0)
            {
                return null;
            }
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            if (send == true)
            {
                sb.Append("→");
            }
            else
            {
                sb.Append("←");
            }
            byte[] bs = (byte[])buffer;
            foreach (var item in bs)
            {
                sb.AppendFormat("{0:X2} ", item);
            }
            return sb.ToString();
        }
        /// <summary>
        /// 消息响应
        /// </summary>
        /// <param name="message">消息</param>
        /// <param name="isAsync">是否异步回调</param>
        protected void RaisePostInfo(string message,bool isAsync=true)
        {
            if (!string.IsNullOrEmpty(deviceInfo))
            {
                message = deviceInfo + message;
            }
            ResponseInfo responseInfo = new ResponseInfo(ResponseInfoType.NotifyInfo, message);
            if (isAsync == true)
            {
                this.Post(responseInfo);
            }
            else
            {
                this.FeedResponseInfo(responseInfo);
            }
        }
        /// <summary>
        /// 异常响应
        /// </summary>
        /// <param name="exception">异常信息</param>
        /// <param name="isAsync">是否异步回调</param>
        protected void RaisePostException(Exception exception,bool isAsync=true)
        {
            if (!string.IsNullOrEmpty(deviceInfo))
            {
                exception = new Exception(deviceInfo + exception.Message);
            }
            ResponseInfo responseInfo = new ResponseInfo(ResponseInfoType.Exception, exception);
            if (isAsync == true)
            {
                this.Post(responseInfo);
            }
            else
            {
                this.FeedResponseInfo(responseInfo);
            }
        }
        /// <summary>
        /// 接收数据记录日志
        /// </summary>
        /// <param name="message">消息</param>
        /// <param name="isAsync">是否异步回调</param>
        protected void RaisePostReceiveLog(string message,bool isAsync=true)
        {
            if (OnResponseInfo == null)
            {
                return;
            }
            ResponseInfo responseInfo = new ResponseInfo(ResponseInfoType.ReceiveLog, message);
            if (isAsync == true)
            {
                this.Post(responseInfo);
            }
            else
            {
                this.FeedResponseInfo(responseInfo);
            }
        }
        /// <summary>
        /// 发送数据记录日志
        /// </summary>
        /// <param name="message">消息</param>
        /// <param name="isAsync">是否异步回调</param>
        protected void RaisePostSendLog(string title,string message, bool isAsync = true)
        {
            if (OnResponseInfo == null)
            {
                return;
            }
            ResponseInfo responseInfo;
            if (string.IsNullOrEmpty(title))
            {
                responseInfo = new ResponseInfo(ResponseInfoType.SendLog, message);
            }
            else
            {
                responseInfo = new ResponseInfo(ResponseInfoType.SendLog,string.Format("【{0}】{1}",title,message));
            }
            if (isAsync == true)
            {
                this.Post(responseInfo);
            }
            else
            {
                this.FeedResponseInfo(responseInfo);
            }
        }
        private Guid communicationID;
        /// <summary>
        /// 通信对象ID
        /// </summary>
        public Guid CommunicationID
        {
            get
            {
                return communicationID;
            }
        }
    }

具体的实现,分成不同的通信方式,TCP客户端的通信代码示例:

///<summary>
    /// TCP连接模式通信
    /// </summary>
    /// <typeparam name="TInputMessageFilter">输入消息过滤器类型</typeparam>
    /// <typeparam name="TOutputMessageFilter">应答消息过滤器类型</typeparam>
    /// <typeparam name="TRequest">请求数据</typeparam>
    /// <typeparam name="TResponse">应答数据</typeparam>
    public class TCPClientCommunication<TInputMessageFilter,TOutputMessageFilter,TRequest,TResponse> 
        : BaseCommunication<TRequest,TResponse>,IDisposable
        where TInputMessageFilter : BaseInPutMessageFilter<TRequest>
        where TOutputMessageFilter : BaseOutPutMessageFilter<TRequest,TResponse>
        where TRequest:BaseRequestData
        where TResponse:BaseResponseData
    {
        /// <summary>
        /// 连接会话
        /// </summary>
        protected TCPConnectSession<TRequest, TResponse> currentConnectSession = null;
        /// <summary>
        /// TCP连接地址
        /// </summary>
        protected IPEndPoint end;
        /// <summary>
        /// 网络连接的IP地址和端口号
        /// </summary>
        private string endPort;
        /// <summary>
        /// 异步写入消息队列,用于异步写入排队
        /// </summary>
        private IMessageFIFO asyncWriteMessageFIFO = null;
        /// <summary>
        /// 发起重连时,尝试不成功下一次连接的间隔时间
        /// </summary>
        protected Int32 periodTimeOut = 500;
        /// <summary>
        /// 通信端口初始化参数
        /// </summary>
        protected TCPClientParameters communicationParamerters;
        /// <summary>
        /// 发送处理锁
        /// </summary>
        private object sendLock = new object();
        /// <summary>
        /// 启动失败用于重连使用
        /// </summary>
        private IMessageFIFO openReconnectFIFO = null;
        /// <summary>
        /// 连接模式构造
        /// </summary>
        ///<param name="pa">通信参数</param>
       
        private TCPClientCommunication(TCPClientParameters pa)
        {
            this.communicationParamerters = pa;
            this.deviceInfo = pa.DeviceInfo;
            this.end = new IPEndPoint(IPAddress.Parse(pa.Ip), pa.PortNO);
            this.endPort = string.Format("{0}:{1}", pa.Ip, pa.PortNO);
        }
        /// <summary>
        /// 构建TCP客户端连接模式通信
        /// </summary>
        /// <param name="pa">通信参数</param>
        /// <returns></returns>
        public static ICommunication<TRequest, TResponse> Create(TCPClientParameters pa)
        {
            ICommunication<TRequest, TResponse> iCommunication = new TCPClientCommunication<TInputMessageFilter, TOutputMessageFilter, TRequest, TResponse>(pa);
            return iCommunication;
        }
        /// <summary>
        /// 打开端口
        /// 如果打开失败,会自动尝试关闭掉
        /// </summary>
        public override void Open()
        {
            try
            {
                bool openFail = false;
                FeedOperateStatus(OperateStatus.Opening);
                OpenReconnectException openReconnectException = null;
                try
                {
                    this.StartConnectNetWork();
                }
                catch (Exception ex)
                {
                    if (communicationParamerters.IsOpenExpConnect == false)
                    {
                        throw ex;
                    }
                    else
                    {
                        this.OpenReconnectFIFO();
                        openFail = true;
                        openReconnectException = new OpenReconnectException(string.Format("网口【{0}】打开失败,失败原因:{1},系统正在尝试重新连接", endPort, ex.Message));
                    }
                }
                this.OpenAsyncWriteMessageFIFO(communicationParamerters.IsAsyncRequest);
                this.OpenRespnoseMessageFIFO();
                System.Threading.Thread.Sleep(100);
                FeedOperateStatus(OperateStatus.Opened);
                if (this.currentConnectSession != null && openReconnectException == null)//启动会话通知
                {
                    TCPConnectSession<TRequest, TResponse> tempSession = this.currentConnectSession;
                    SessionInfo sessionInfo = new SessionInfo(tempSession.SessionID, tempSession.LocalPortName, tempSession.RemotePortName, CommunicationID);
                    RaiseConnectSession(sessionInfo);
                }
                if (openFail == true)
                {
                    if (communicationParamerters.IsOpenExpConnect == true)
                    {
                        if (openReconnectException != null)
                        {
                            System.Threading.Thread.Sleep(200);
                            if (openReconnectFIFO != null && openReconnectFIFO.IsOpened == true)
                            {
                                openReconnectFIFO.Post(openReconnectException);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                try
                {
                    this.CloseAsyncWriteMessageFIFO();
                    this.CloseResponseMessageFIFO();
                    this.StopConnectNetWork();
                }
                catch { }
                Exception portExcp = new Exception(string.Format("网口【{0}】打开失败,失败原因:{1}", endPort, ex.Message));
                RaisePostException(portExcp);
                throw portExcp;
            }
        }
        /// <summary>
        /// 响应消息队列启动
        /// </summary>
        protected virtual void OpenReconnectFIFO()
        {
            if (openReconnectFIFO == null)
            {
                openReconnectFIFO = MessageFIFOFactory.Create(MessageFIFOType.IOCPMessageFIFO);
                openReconnectFIFO.Excute += openReconnectFIFO_Excute;
            }
            if (openReconnectFIFO != null && openReconnectFIFO.IsOpened == false)
            {
                openReconnectFIFO.Start();
            }
        }
        /// <summary>
        /// 用于启动失败,重连托管
        /// </summary>
        /// <param name="obj"></param>
        void openReconnectFIFO_Excute(object obj)
        {
            if (obj is OpenReconnectException)
            {
                this.ExcpReConnect((OpenReconnectException)obj);
            }
        }
        /// <summary>
        /// 用于启动失败,重连托管消息队列关闭
        /// </summary>
        protected virtual void CloseReconnectFIFO()
        {
            if (openReconnectFIFO != null && openReconnectFIFO.IsOpened == true)
            {
                System.Threading.Thread.Sleep(2000);
                openReconnectFIFO.ForceStop();
            }
            openReconnectFIFO = null;
        }
      
        /// <summary>
        /// 开始TCP网络连接
        /// </summary>
        private void StartConnectNetWork()
        {

通信对外提供,是通过通信工厂构建:

/// <summary>
    /// 通信工厂构建
    /// </summary>
    /// <typeparam name="TInputMessageFilter">输入消息构造器类型</typeparam>
    /// <typeparam name="TOutputMessageFilter">应答消息过滤器类型</typeparam>
    /// <typeparam name="TRequest">请求数据</typeparam>
    /// <typeparam name="TResponse">应答数据</typeparam>
    public class CommunicationFactory<TInputMessageFilter, TOutputMessageFilter, TRequest, TResponse>
        where TInputMessageFilter : BaseInPutMessageFilter<TRequest>
        where TOutputMessageFilter : BaseOutPutMessageFilter<TRequest, TResponse>
        where TRequest : BaseRequestData
        where TResponse : BaseResponseData
    {
        /// <summary>
        /// 通信工厂构建
        /// </summary>
        /// <param name="paramerters">通信启动设置参数</param>
        /// <returns>
        /// 返回通信对象
        /// </returns>
        public static ICommunication<TRequest, TResponse> Create(BaseCommunicationParameters paramerters)
        {
            ICommunication<TRequest, TResponse> iCommunication = null;
            if (paramerters is SerialParameters)
            {
                SerialParameters tempParamerters = (SerialParameters)paramerters;
                iCommunication = SerialPortCommunication<TInputMessageFilter, TOutputMessageFilter, TRequest, TResponse>.Create(tempParamerters);
            }
            else if (paramerters is TCPClientParameters)
            {
                TCPClientParameters tempParamerters = (TCPClientParameters)paramerters;
                iCommunication = TCPClientCommunication<TInputMessageFilter, TOutputMessageFilter, TRequest, TResponse>.Create(tempParamerters);
            }
            else if (paramerters is TCPServerParameters)
            {
                TCPServerParameters tempParamerters = (TCPServerParameters)paramerters;
                iCommunication = TCPServerCommunication<TInputMessageFilter, TOutputMessageFilter, TRequest, TResponse>.Create(tempParamerters);
            }
            else if (paramerters is TCPAsyncServerParameters)
            {
                TCPAsyncServerParameters tempParamerters = (TCPAsyncServerParameters)paramerters;
                iCommunication = TCPAsyncServerCommunication<TInputMessageFilter, TOutputMessageFilter, TRequest, TResponse>.Create(tempParamerters);
            }
            else if (paramerters is UDPAsyncServerParameters)
            {
                UDPAsyncServerParameters tempParamerters = (UDPAsyncServerParameters)paramerters;
                iCommunication = UDPAsyncServerCommunication<TInputMessageFilter, TOutputMessageFilter, TRequest, TResponse>.Create(tempParamerters);
            }
            else if (paramerters is HttpClientParameters)
            {
                HttpClientParameters tempParamerters = (HttpClientParameters)paramerters;
                iCommunication = HttpClientCommunication<TInputMessageFilter, TOutputMessageFilter, TRequest, TResponse>.Create(tempParamerters);
            }
            return iCommunication;
        }
    }

通信组件具体调用Demo,以IncJet喷码机通信协议为例,Demo地址:http://download.csdn.net/detail/gongbenwen/9607473。


其中核心部分代码还是对四个基础类的派生实现:


请求数据:

 public class IncjetRequest : Trace.Common.Communication.Request.BaseRequestData
    {
        /// <summary>
        /// 传输的数据
        /// </summary>
        public byte[] DataBuffer;
        /// <summary>
        /// 包头数据
        /// </summary>
        public byte STX = 0x02;
        /// <summary>
        /// 是否进行数据和校验
        /// </summary>
        public bool IsCheckSum = false;
        /// <summary>
        /// 是否启用传输消息序列号
        /// </summary>
        public bool IsUseTransmitSequenceNumber = false;
        /// <summary>
        /// 传输的消息序列号
        /// </summary>
        public int TransmitSequenceNumber = 0;
        /// <summary>
        /// 传输消息类型或消息命令
        /// </summary>
        public byte MessageID=0x00;
        /// <summary>
        /// 包尾数据  
        /// </summary>
        public byte ETX = 0x03;
    }
请求消息处理器:
 public class IncJetInputFilter : Trace.Common.Communication.Message.BaseInPutMessageFilter<IncjetRequest>
    {
        /// <summary>
        /// 构建发送数据封包
        /// </summary>
        /// <param name="requestData">请求数据</param>
        /// <returns>
        /// 返回构建数据封包
        /// </returns>
        public override byte[] ProcessToSendBuffer(IncjetRequest requestData)
        {
            byte[] numberBytes=this.NumberBytesToFollow(requestData.DataBuffer);
            byte transmitSequenceNumber=this.GetTransmitSequenceNumber(requestData.TransmitSequenceNumber,requestData.IsUseTransmitSequenceNumber);
            byte checkSum=this.CheckSum(transmitSequenceNumber,requestData.MessageID,requestData.DataBuffer,requestData.ETX,requestData.IsCheckSum);
            MessageStatckPack messageStatckPack = new MessageStatckPack();
            messageStatckPack.PushByte(requestData.STX);
            messageStatckPack.PushBytes(numberBytes);
            messageStatckPack.PushByte(checkSum);
            messageStatckPack.PushByte(transmitSequenceNumber);
            messageStatckPack.PushByte(requestData.MessageID);
            messageStatckPack.PushBytes(requestData.DataBuffer);
            messageStatckPack.PushByte(requestData.ETX);
            return messageStatckPack.GetDataBuffer();
        }
        /// <summary>
        /// 获取数据长度
        /// </summary>
        /// <param name="dataBuffer">传输的数据</param>
        /// <returns></returns>
        public  byte[] NumberBytesToFollow(byte[] dataBuffer)
        {
            int length = 4 + dataBuffer.Length;
            return BitConverter.GetBytes(length);
        }
        /// <summary>
        /// 进行校验和处理
        /// </summary>
        /// <param name="tarnsmitSequenceNum">传输序列号</param>
        /// <param name="messageID">消息ID</param>
        /// <param name="dataBuffer">传输的数据</param>
        /// <param name="etx">包尾</param>
        /// <param name="isUse">是否启用</param>
        /// <returns></returns>
        public byte CheckSum(byte tarnsmitSequenceNum, byte messageID, byte[] dataBuffer, byte etx, bool isUse = false)
        {
            if (isUse == false)
            {
                return 0x00;
            }
            byte checkSum = tarnsmitSequenceNum;
            checkSum += messageID;
            for (int i = 0; i < dataBuffer.Length; i++)
            {
                checkSum += dataBuffer[i];
            }
            checkSum += etx;
            return checkSum;
        }
        /// <summary>
        /// 获取传输序列号
        /// </summary>
        /// <param name="number">序列号</param>
        /// <param name="isUse">是否启用</param>
        /// <returns></returns>
        public byte GetTransmitSequenceNumber(int number, bool isUse = false)
        {
            if (isUse == false)
            {
                number = 0;
                return 0x00;
            }
            return (byte)(0xFF & number); ;
        }
    }

应答数据:

 public class IncJetResponse : Trace.Common.Communication.Response.BaseResponseData
    {
        private byte messageId = 0x00;
        /// <summary>
        /// 消息ID
        /// </summary>
        public byte MessageID
        {
            get
            {
                return messageId;
            }
            set
            {
                messageId = value;
            }
        }
        public byte[] messageData;
        /// <summary>
        /// 消息体数据
        /// </summary>
        public byte[] MessageData
        {
            get
            {
                return messageData;
            }
            set
            {
                messageData = value;
            }
        }
        private Exception exception;
        /// <summary>
        /// 异常信息
        /// </summary>
        public Exception Exception
        {
            get
            {
                return exception;
            }
            set
            {
                exception = value;
            }
        }
        /// <summary>
        /// 将字节数组转化成可显示的字符串
        /// </summary>
        /// <param name="buffer"></param>
        /// <returns></returns>
        private string ByteToString()
        {
            if (messageData == null)
            {
                return string.Empty;
            }
            StringBuilder sb = new StringBuilder();
            foreach (var item in messageData)
            {
                sb.AppendFormat("{0:X2} ", item);
            }
            return sb.ToString();
        }
        private IncJetReplyMessage data;
        /// <summary>
        /// 数据
        /// </summary>
        public IncJetReplyMessage Data
        {
            get
            {
                return data;
            }
            set
            {
                data = value;
            }
        }
       
      
    }


应答数据消息处理器:

public class IncJetOutputFilter : Trace.Common.Communication.Message.BaseOutPutMessageFilter<IncjetRequest, IncJetResponse>
    {
        private IMessageFilterHelper messageFilterHelper = null;
        /// <summary>
        /// 包头
        /// </summary>
        private byte[] start = new byte[] { 0x02 };
        /// <summary>
        /// 包尾
        /// </summary>
        private byte[] end = new byte[] { 0x03 };
        public IncJetOutputFilter()
        {
            messageFilterHelper = new MessageFilterFixStartLengthHelper(start, 4);
        }
        protected override void InputBufferData(string sessionID, byte[] buffer)
        {
            messageFilterHelper.InputBufferData(buffer);
        }
        protected override IncJetResponse GetNextResponse()
        {
            byte[] tempBuffer = messageFilterHelper.GetNextData();
            if (tempBuffer == null || tempBuffer.Length == 0)
            {
                return null;
            }
            IncJetResponse tempJetResponse = this.JetResponse(tempBuffer);
            return tempJetResponse;
        }
        /// <summary>
        /// 将字节数组转化成对应的字符串
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="send"></param>
        /// <returns></returns>
        protected string BytesToHexString(byte[] buffer, bool send)
        {
            if (buffer == null || buffer.Length == 0)
            {
                return null;
            }
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            if (send == true)
            {
                sb.Append("→");
            }
            else
            {
                sb.Append("←");
            }
            byte[] bs = (byte[])buffer;
            foreach (var item in bs)
            {
                sb.AppendFormat("{0:X2} ", item);
            }
            return sb.ToString();
        }
        private IncJetResponse JetResponse(byte[] blockBuffer)
        {
            IncJetResponse jetResponse = new IncJetResponse();
            try
            {
                MessageStatckSplit messageStatckSplit = new MessageStatckSplit(blockBuffer);
                string logData = BytesToHexString(blockBuffer, false);
                byte chk;
                if (messageStatckSplit.PopByte(out chk) == false)
                {
                    throw new Exception(string.Format("数据包{0}获取校验位失败", logData));
                }
                byte[] leftBuffer = messageStatckSplit.GetLeftDataBuffer();
                byte tempChk = 0x00;
                for (int i = 0; i < leftBuffer.Length; i++)
                {
                    tempChk += leftBuffer[i];
                }
                if (chk != tempChk)
                {
                    throw new Exception(string.Format("数据包{0}校验失败", logData));
                }
                byte sequenceNum;
                if (messageStatckSplit.PopByte(out sequenceNum) == false)
                {
                    throw new Exception(string.Format("数据包{0}获取传输位失败", logData));
                }
                byte messageID;
                if (messageStatckSplit.PopByte(out messageID) == false)
                {
                    throw new Exception(string.Format("数据包{0}获取传MessageID失败", logData));
                }
                jetResponse.MessageID = messageID;
                byte[] messageData = messageStatckSplit.GetLeftDataBuffer();
                jetResponse.messageData = messageData;
                IncJetReplyMessage replyMessage = null;
                if (jetResponse.MessageID == ACKMessage.MessageID)
                {
                    replyMessage = new ACKMessage();
                }
                else if (jetResponse.MessageID == ErrorMessageReply.MessageID)
                {
                    replyMessage = new ErrorMessageReply();
                }
                else if (jetResponse.MessageID == DynamicDataPrintedTM1Reply.MessageID)
                {
                    replyMessage = new DynamicDataPrintedTM1Reply();
                }
                else if (jetResponse.MessageID == TMPurgePageReply.MessageID)
                {
                    replyMessage = new TMPurgePageReply();
                }
                else if (jetResponse.MessageID == PrinterStateReply.MessageID)
                {
                    replyMessage = new PrinterStateReply();
                }
                else if (jetResponse.MessageID == ContactImagerReplay.MessageID)
                {
                    replyMessage = new ContactImagerReplay();
                }
                else if (jetResponse.MessageID == InkLevelsReply.MessageID)
                {
                    replyMessage = new InkLevelsReply();
                }
                else if (jetResponse.MessageID == NumLeftToPrintReply.MessageID)
                {
                    replyMessage = new NumLeftToPrintReply();
                }
                else if (jetResponse.MessageID == TMGuiPrintButtonChangedReply.MessageID)
                {
                    replyMessage = new TMGuiPrintButtonChangedReply();
                }
                else if (jetResponse.MessageID == TMLowInkReply.MessageID)
                {
                    replyMessage = new TMLowInkReply();
                }
                if (replyMessage == null)
                {
                    throw new Exception(string.Format("消息ID:{0}对应消息解析失败", jetResponse.MessageID));
                }
                replyMessage.SetData(jetResponse.MessageData);
                jetResponse.Data = replyMessage;
            }
            catch (Exception ex)
            {
                jetResponse.Exception = ex;
            }
            return jetResponse;
        }
    } 

通信构建:

 private void Start()
        {
            try
            {
                string ip = this.tB_IP.Text.Trim();
                int receivePort = Convert.ToInt32(this.tBReceivePort.Text.Trim());
                BaseCommunicationParameters receivePa = new TCPClientParameters(ip, receivePort);
                receivePa.IsOpenExpConnect = true;
                receivePa.DeviceInfo = "IncJetReceive";
                if (iReceiveCommunication == null)
                {
                    iReceiveCommunication = CommunicationFactory<IncJetInputFilter, IncJetOutputFilter, IncjetRequest, IncJetResponse>.Create(receivePa);
                    iReceiveCommunication.OnResponseBuffer += iCommunication_OnResponseBuffer;
                    iReceiveCommunication.OnResponseInfo += iReceiveCommunication_OnResponseInfo;
                    iReceiveCommunication.OnOperateStaus += iSendCommunication_OnOperateStaus;
                }
                if (iReceiveCommunication.IsOpen == false)
                {
                    iReceiveCommunication.Open();
                }
            }
            catch (Exception ex)
            {
                this.Invoke(new MessShow(ShowMessage),ex.Message);
                return;
            }
            try
            {
                string ip = this.tB_IP.Text.Trim();
                int sendPort = Convert.ToInt32(this.tBSendPort.Text.Trim());
                BaseCommunicationParameters paSend = new TCPClientParameters(ip, sendPort);
                paSend.IsOpenExpConnect = true;
                paSend.DeviceInfo = "IncJetSend";
                if (iSendCommunication == null)
                {
                    iSendCommunication = CommunicationFactory<IncJetInputFilter, IncJetOutputFilter, IncjetRequest, IncJetResponse>.Create(paSend);
                    iSendCommunication.OnResponseBuffer += iCommunication_OnResponseBuffer;
                    iSendCommunication.OnResponseInfo += iReceiveCommunication_OnResponseInfo;
                    iSendCommunication.OnOperateStaus += iSendCommunication_OnOperateStaus;
                    iSendCommunication.OnSessionAdded += iSendCommunication_OnSessionAdded;
                }
                if (iSendCommunication.IsOpen == false)
                {
                    iSendCommunication.Open();
                }
               
            }
            catch (Exception ex)
            {
                this.Invoke(new MessShow(ShowMessage), ex.Message);
                return;
            }
            this.Invoke(new MessShow(ShowMessage), "started");
            
        }



  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值