王峥 牛盂杰 张莹 李晓东
摘要:论述了一种MES中报文的处理方法,包括报文封装类设计,通讯接口设计,数据库设计等内容。描述了.net框架下端口监听及stream流传输的程序设计方法。
关键词:mes 报文 socket 端口监听 stream流
本文阐述了一种基于socket协议的MES二级系统报文的处理方法。报文是MES系统普遍采用的信息传输方式,具有组成灵活,传输可控,解读方便的特点。设计报文的处理方式,是MES系统重要的组成部分。本项目是一个镀锡线电控系统的MES二级子系统运行稳定,传输可靠。在此简单阐述—下报文的处理方法。
报文处理方法包含以下几个主要环节
1,定义钢卷钢种数据信息PDI,此类主要用于生成报文的各种参数。报文处理需要的元素,都封装成类,再进行实例化调用,这样程序的代码重用及组装都很方便。
public class PDI
{
public int flag{ get; set;}∥钢种标志
public int ID{ get; set;}∥钢种ID
public string Schedule_Code{ get; set;}∥计划代码
private string _coil_no一…I;∥私有变量卷号
pulolic string Coil_NO∥对私有变量的getter和setter操作
{
get
{
if (!string.IsNullOrEmpty(_coil_no》
return _coil_no.ToUpper();
else
return””:
l
set{ _coil_no - value;}
}
public string Schedule_Type{ get; set;}//,//各种钢卷属性的操作方法
public string RepairFlag{ get; set;)
public string Repair_Type{ get; set;}
public int IsDummy{ get; set;}
}
2,报文定义类,此处定义报文封装类,包括各种操作属性,比如ID,生产线代码,请求时间,回应时间,状态,发送目标,回答目标,报文主体内容等。此报文将进入报文池,以队列方式,先进入池的报文,被先处理发送。
public class DBMAILBOX
{
public int ID{ get; set;}∥///报文队列代码
public int Plant_ID{ get; set;}
public int RequestNo{ get; set;}
public DateTime RequestDate{ get; set;}
public DateTime ReplyDate{ get; set;}
public int Status{ get; set;}
public string SendTo{ get; set;}
public string ReplyTo{ get; set;}
public int IDM{ get; set;}厂/∥报文标志代码
public byte[l Msg{ get; set;}////报文内容
publicbyte[l MsgReply{ get; set;}
}
3,组合报文体框架,此处生成报文体对象,根据报文种类(即IDM报文标志),调用对应的报文生成方法,返回报文内容,与其他属性构成报文主体,进入数组,形成报文队列。
DBMAILBOX m—new DBMAILBOX();/////报文对象
m.Plant_ID -0;
m.IDM -2965;∥/∥//新生成的报文为2965
m.Msg—msg.MSG2965(p,setup);/‘∥//报文生成方法,返回报文内容
m.SendTo -”L1C”;/////////报文发送属性
m.RequestDate - DateTime.Now;
m.Reply_Date - DateTime.Now;
m.ReplyTo -llL2Serverll;
m。Status -0:
mail.Add(m);////////把报文内容加入数组mail,形成报文队列。
4,组合报文体,此处形成报文内容,不含其它属性,只是整个报文.dlomailbox的msg部分,也就是向一级系统实际发送的报文内容。
public Byte[]MSG2965(int intMSGPORl, intintMSGPOR2)///////
{
this.MSG_ID - 2965;////報文ID
this.MSG_I。EN—l6;///////报文长度,第一次赋值,作用是电文体开始赋值的位置,2965电文的卷号的开始位置为16,下面的循环中,根据this.MSG_I。EN的初始值,开始给电文体赋值,MSGLEN也不断增加
this.SetString(p.Coil_NO,20,l l,0);///////向电文体写入string
str - DoString.toLongString(str, len,f,itype);////DoString是静态类,将str补充到len长度(不
足时),此时str是Coil_NO卷号,保证卷号长度固定
//////以下是报文各段属性赋值,简略
this.SetSwapValue《Int16)intMSGPORl);/////向电文体写入开卷机请求数据l
this. SetSwapValue《Int16)intMSGPOR2);/////向电文体写入开卷机请求数据2
return this.GetBytes();/////加上报上报头head(最终调用sethead0方法),形成最终报文体
}
5,socket端口监听类。本项目采用socket方式接收和发送电文,通过不同端口进行收发,提高了报文处理速度。利用.NET框架的socket封装类,简化了程序代码。采用多线程方式,对收发动作进行新建线程方式,实现并发处理。.NET框架用IPEndPoint对象来表示一个特定的IP地址和端口的组合,应用该对象的场景多是在将socket绑定到本地地址。
∥接收来自L1-级系统的报文
public class MsgFromLI:ThreadService////建立线程
{
public ThreadStatus status—null;
TcpListener server=null;///////定义监听类的对象
IPEndPoint ipLocalEndPoint=null;
pulolic MsgFromLl()///构造函数,进行初始化,建立监听通道
{
ipLocaIEndPoint - newIPEndPoint(IPAddress.Parse("10.36.1.225"), 3001);
//∥监听一级系统PLC的ip和端口
status—new ThreadStatus();////建立线程状态对象
)
public void Start0
{
status.run_flag - true;
server - new TcpListener(ipLocalEndPoint);//,//监听类实例化
server. Start();//∥启动监听
status.starttime - DoDateTime.getNovrString();
TcpClient client—null;
while (status.run_flag)
{
if (client一一null』!client.Connected)
{
client - server.AcceptTcpClient();////開始接收请求
client.ReceiveBufferSize -2016;/∥//接收缓冲区长度
}
client.ReceiveBufferSize - 2016;
ByteLl bytes - new Byte[client.ReceiveBufferSizel;//接收报文的字符串初始化
NetworkStream stream — client.GetStream();/∥//建立stream流,进行传输
stream.Read(bytes,O,bytes.Length);////读入stream流数据进入字符串
client. Close();
client—null;
}
}
}
6,发送报文
public void Start0
{
status.run_flag - true;
status.start_time - DoDate-Fime.getNo.nrString();
string rernoteIP~"10.36.1.135";////socket客户端连接远程服务器地址
int remotePort - 3003;
string localIP一"10.36.1.225";
int localPort - 2003;
MSGTcpClient client - nevr MSGTcpClient(localIP. localPort, remoteIP, remotePort);
DBMAILBOX msg—new DBMAILBOX();
while (status.run_flag)
{
if(! client. Connect(》/////client初始化要建立连接
{
Thread.Sleep(2000);
continue:
}
msg -Scan();//∥//msg存人扫描的信息结果,形成电文
msg.Status一1;∥∥/msg不为空
client.SendOnce(msg.Msg.0,2016);//,//发送电文,
∥∥/上面msg -Scan();//∥//IIlsg存入扫描的信息结果,形成电文
}
}
发送动作语句
public Boolean SendOnceCoyte[l buffer .int offset,int size)
{
stream一client.GetStream();//
∥返回用于发送和接收数据的System.Net.Sockets.NetworkStream。
stream.Write(buffer, offset.slze);//∥向stream的对端发出数据
return true;
}