在协议栈实现的基础上,如何将封包后字节流发送到远端设备,或从远端设备接收封包的字节流,则需要通信层辅助实现,通信层负责连接构建、监听、会话管理等,是在远程方法调用,代码编写的最底一层,其中连接的管理、数据调度的分离等,一直是底层通信服务端开发人员在不断解决的问题,要做到更多的性能优化,比如异步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");
}