无线监控系统之三-------测试与扩展
无线监控系统之三-------测试与扩展 测试是一个程序必不可少的部分,一个程序至少需要检验是否可以按要求运行,有源码的朋友也许会发现源码中有一些临时的嵌套在程序中的测试用例,对某些用例我做一个简单的介绍。
测试一:该测试主要用于在串口通讯还没连通时的,屏蔽掉获取串口数据的代码,给数据数组初始化一个正常的数据帧,测试用户显示界面能否显示正常的数据。
上面两个测试主要是用于测试串口数据接受前后检测数据在程序中是否可以正常传输,由于前面的程序都是根据类模型图一口气写完的,一开始还担心写得太乱,会调死人去~...~,开始时碰到了一点小问题,我屏蔽掉了TimIntvArth.cs中的一些数据限制代码(见下程序),哈哈,通了。。。高兴啊,小问题,易解决了。
下面我重点讲讲系统设计可以扩展的地方,呵呵,这也许是设计模式设计的好处吧,再次推荐GOF的<<设计模式--可复用面向对象软件的基础>>一书,你会有异想不到的收获。
系统可扩展的第一个地方----通讯方式的扩展,大家可以看UML图(上位机与下位机数据通讯方式接口图,呵呵,朋友再点击一次第一部分喽),我现在实现的是串口通讯的程序,有兴趣的朋友可以实现其它三种通讯中的一种,然后只要在主窗口把通讯方式在cFlag类中设定为你需要的通讯方式即可。
系统可扩展的第二个地方---数据帧的扩展(数据帧接口图),通讯系统的数据帧格式并不是一成不变的,数据帧会根据实际需要而增加,如果我们把所有的数据帧都写在一个类里,到时累死的是我们,烦死的是后来者了。。。。刚好,这个部分我可以举个例子,细心的朋友可能会看到资源管理器中的DATAFRAME包中有两个类我以前没介绍过----TimIntvArth.cs和TimIntvData.cs,这两个类是用来实现系统向外界发送数据,看看源码吧~~
using System;
using System.Collections.Generic;
using System.Text;
/************
* 功能:采集时间间隔数据帧处理
* **********************/
namespace LOGICDEAL.DATAFRAME
{
class TimIntvArth:ArthFrameInter
{
private int n = 22, m = 9;
public byte[] dealData(byte[] framdata) //数据帧处理函数
{
if (!framdata[0].ToString("x").Trim().Equals("aa")) return null;
if (!framdata[2].ToString("x").Trim().Equals("11")) return null;
if ((!framdata[4].ToString("x").Trim().Equals("3")) && (!framdata[4].ToString("x").Trim().Equals("2"))) return null;
int textds = 0;
for (int j = 0; j < n - 2; j++) //计算前20字节数之和
{
textds += Convert.ToInt32(COMMONDEAL.DataConversion.Hex2Ten(framdata[j].ToString("x").Trim()));
}
int efficy = Convert.ToInt32(COMMONDEAL.DataConversion.Hex2Ten(framdata[n - 2].ToString("x").Trim() + framdata[n - 1].ToString("x").Trim())); //计算效验码值
if (textds != efficy) { return null; }
byte[] adata = new byte[m];
adata[0] = framdata[5]; //提取数据,2字节
adata[1] = framdata[6];
adata[2] = framdata[13]; //提取源地址,2字节
adata[3] = framdata[14];
adata[4] = framdata[15]; //提取网络地址,2字节
adata[5] = framdata[16];
adata[6] = framdata[17]; //网络号,1字节
adata[7] = framdata[18]; //提取通道,1字节
adata[8] = framdata[19]; //提取RSSI,1字节
return adata;
}
}
}
系统可扩展的第三个地方---用户窗体与数据逻辑层的处理线程类(见用户窗体与数据逻辑层的处理线程类图),当初也不知道为什么要弄个线程类,呵呵,现在可想清楚了,这个线程啊主要是用来进行各数据帧的业务处理的,包括从获取通讯方式、获取数据帧类型和从通讯端口获取(传送)数据,这是个策略性问题了,通讯方式和数据帧类型的组合就是一种策略,如为采集时间间隔数据帧格式设置的TimIntvThd类。
系统可扩展的第四个地方---用户窗口公共接口(见用户窗口公共接口图),这个接口主要用来为各用户窗体需要的数据处理线程提供一个统一接口,用户窗体中可以根据需要来设计一个或多个数据处理线程,如扩展中的TimIntevForm.窗体,代码如下:
第三部分就这样吧,设计肯定有许多漏洞,望各位多提意见了。。。
测试一:该测试主要用于在串口通讯还没连通时的,屏蔽掉获取串口数据的代码,给数据数组初始化一个正常的数据帧,测试用户显示界面能否显示正常的数据。
TemVlueThd.cs
dataa = new byte[21]{ 0xaa, 0x01, 0x10, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x11, 0x02, 0x02, 0x00, 0xe5}; //读取数据
//if (cci.getdata() == null) return;
//Array.Copy(cci.getdata(), dataa, n);
dataa = new byte[21]{ 0xaa, 0x01, 0x10, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x11, 0x02, 0x02, 0x00, 0xe5}; //读取数据
//if (cci.getdata() == null) return;
//Array.Copy(cci.getdata(), dataa, n);
测试二:我在用户数据显示界面上作了一个数据结果测试文本框,用来测试需要显示的数据值(十六进制转换成十进制后的数据),以便于直观的观察程序数据传输链路是否已经打通。
DataDisplyForm.cs
public void showTemDisplyValue(byte[] dataaa) //委托,数据处理及显示
{
string v = Convert.ToString(COMMONDEAL.DataConversion.Hex2Ten(COMMONDEAL.DataConversion.LenByte(dataaa[0].ToString(), 2) + COMMONDEAL.DataConversion.LenByte(dataaa[1].ToString(), 2))); //获取传送的数据
//txttest.Text = COMMONDEAL.DataConversion.LenByte(tdata[0].ToString("x").Trim() + tdata[1].ToString("x").Trim(), 2); //测试
txttest.Text = v; //测试
string rv = null;
........
........
}
public void showTemDisplyValue(byte[] dataaa) //委托,数据处理及显示
{
string v = Convert.ToString(COMMONDEAL.DataConversion.Hex2Ten(COMMONDEAL.DataConversion.LenByte(dataaa[0].ToString(), 2) + COMMONDEAL.DataConversion.LenByte(dataaa[1].ToString(), 2))); //获取传送的数据
//txttest.Text = COMMONDEAL.DataConversion.LenByte(tdata[0].ToString("x").Trim() + tdata[1].ToString("x").Trim(), 2); //测试
txttest.Text = v; //测试
string rv = null;
........
........
}
上面两个测试主要是用于测试串口数据接受前后检测数据在程序中是否可以正常传输,由于前面的程序都是根据类模型图一口气写完的,一开始还担心写得太乱,会调死人去~...~,开始时碰到了一点小问题,我屏蔽掉了TimIntvArth.cs中的一些数据限制代码(见下程序),哈哈,通了。。。高兴啊,小问题,易解决了。
TimIntvArth.cs
public byte[] dealData(byte[] framdata) //数据帧处理函数
{
//if (!framdata[0].ToString("x").Trim().Equals("aa")) return null;
//if (!framdata[2].ToString("x").Trim().Equals("11")) return null;
//if ((!framdata[4].ToString("x").Trim().Equals("3")) && (!framdata[4].ToString("x").Trim().Equals("2"))) return null;
// int textds = 0;
// for (int j = 0; j < n - 2; j++) //计算前20字节数之和
//{
//textds += Convert.ToInt32(COMMONDEAL.DataConversion.Hex2Ten(framdata[j].ToString("x").Trim()));
// }
//int efficy = Convert.ToInt32(COMMONDEAL.DataConversion.Hex2Ten(framdata[n - 2].ToString("x").Trim() + framdata[n - 1].ToString("x").Trim())); //计算效验码值
// if (textds != efficy) { return null; }
........
........
}
public byte[] dealData(byte[] framdata) //数据帧处理函数
{
//if (!framdata[0].ToString("x").Trim().Equals("aa")) return null;
//if (!framdata[2].ToString("x").Trim().Equals("11")) return null;
//if ((!framdata[4].ToString("x").Trim().Equals("3")) && (!framdata[4].ToString("x").Trim().Equals("2"))) return null;
// int textds = 0;
// for (int j = 0; j < n - 2; j++) //计算前20字节数之和
//{
//textds += Convert.ToInt32(COMMONDEAL.DataConversion.Hex2Ten(framdata[j].ToString("x").Trim()));
// }
//int efficy = Convert.ToInt32(COMMONDEAL.DataConversion.Hex2Ten(framdata[n - 2].ToString("x").Trim() + framdata[n - 1].ToString("x").Trim())); //计算效验码值
// if (textds != efficy) { return null; }
........
........
}
下面我重点讲讲系统设计可以扩展的地方,呵呵,这也许是设计模式设计的好处吧,再次推荐GOF的<<设计模式--可复用面向对象软件的基础>>一书,你会有异想不到的收获。
系统可扩展的第一个地方----通讯方式的扩展,大家可以看UML图(上位机与下位机数据通讯方式接口图,呵呵,朋友再点击一次第一部分喽),我现在实现的是串口通讯的程序,有兴趣的朋友可以实现其它三种通讯中的一种,然后只要在主窗口把通讯方式在cFlag类中设定为你需要的通讯方式即可。
系统可扩展的第二个地方---数据帧的扩展(数据帧接口图),通讯系统的数据帧格式并不是一成不变的,数据帧会根据实际需要而增加,如果我们把所有的数据帧都写在一个类里,到时累死的是我们,烦死的是后来者了。。。。刚好,这个部分我可以举个例子,细心的朋友可能会看到资源管理器中的DATAFRAME包中有两个类我以前没介绍过----TimIntvArth.cs和TimIntvData.cs,这两个类是用来实现系统向外界发送数据,看看源码吧~~
using System;
using System.Collections.Generic;
using System.Text;
/************
* 功能:采集时间间隔数据帧
**********************/
namespace LOGICDEAL.DATAFRAME
{
class TimIntvData:DataFrameInter
{
private ArthFrameInter afi = null; //工厂模式:对应的数据帧处理类
private int n=18, m=9;
public TimIntvData()
{
}
public byte[] dealFrame(byte[] frame) //接收数据帧函数,温度值数据帧长度为21字节
{
if (afi.dealData(frame) == null) return null;
byte[] adata = new byte[m]; //需要输出的字节数组,长度为9字节
Array.Copy(afi.dealData(frame), adata, m);
//adata = afi.dealData(frame);
return adata;
}
public byte[] sendFrame() //发送数据帧函数
{
byte[] a = new byte[10];
return a;
}
public void setAFI() //获取数据帧处理类实例
{
this.afi = new TimIntvArth();
}
}
}
using System.Collections.Generic;
using System.Text;
/************
* 功能:采集时间间隔数据帧
**********************/
namespace LOGICDEAL.DATAFRAME
{
class TimIntvData:DataFrameInter
{
private ArthFrameInter afi = null; //工厂模式:对应的数据帧处理类
private int n=18, m=9;
public TimIntvData()
{
}
public byte[] dealFrame(byte[] frame) //接收数据帧函数,温度值数据帧长度为21字节
{
if (afi.dealData(frame) == null) return null;
byte[] adata = new byte[m]; //需要输出的字节数组,长度为9字节
Array.Copy(afi.dealData(frame), adata, m);
//adata = afi.dealData(frame);
return adata;
}
public byte[] sendFrame() //发送数据帧函数
{
byte[] a = new byte[10];
return a;
}
public void setAFI() //获取数据帧处理类实例
{
this.afi = new TimIntvArth();
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
/************
* 功能:采集时间间隔数据帧处理
* **********************/
namespace LOGICDEAL.DATAFRAME
{
class TimIntvArth:ArthFrameInter
{
private int n = 22, m = 9;
public byte[] dealData(byte[] framdata) //数据帧处理函数
{
if (!framdata[0].ToString("x").Trim().Equals("aa")) return null;
if (!framdata[2].ToString("x").Trim().Equals("11")) return null;
if ((!framdata[4].ToString("x").Trim().Equals("3")) && (!framdata[4].ToString("x").Trim().Equals("2"))) return null;
int textds = 0;
for (int j = 0; j < n - 2; j++) //计算前20字节数之和
{
textds += Convert.ToInt32(COMMONDEAL.DataConversion.Hex2Ten(framdata[j].ToString("x").Trim()));
}
int efficy = Convert.ToInt32(COMMONDEAL.DataConversion.Hex2Ten(framdata[n - 2].ToString("x").Trim() + framdata[n - 1].ToString("x").Trim())); //计算效验码值
if (textds != efficy) { return null; }
byte[] adata = new byte[m];
adata[0] = framdata[5]; //提取数据,2字节
adata[1] = framdata[6];
adata[2] = framdata[13]; //提取源地址,2字节
adata[3] = framdata[14];
adata[4] = framdata[15]; //提取网络地址,2字节
adata[5] = framdata[16];
adata[6] = framdata[17]; //网络号,1字节
adata[7] = framdata[18]; //提取通道,1字节
adata[8] = framdata[19]; //提取RSSI,1字节
return adata;
}
}
}
系统可扩展的第三个地方---用户窗体与数据逻辑层的处理线程类(见用户窗体与数据逻辑层的处理线程类图),当初也不知道为什么要弄个线程类,呵呵,现在可想清楚了,这个线程啊主要是用来进行各数据帧的业务处理的,包括从获取通讯方式、获取数据帧类型和从通讯端口获取(传送)数据,这是个策略性问题了,通讯方式和数据帧类型的组合就是一种策略,如为采集时间间隔数据帧格式设置的TimIntvThd类。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
/************
* 功能:采集时间间隔数据帧线程类
* **********************/
namespace LOGICDEAL.DEALTHREAD
{
public class TimIntvThd:DealThread
{
private COMMUNICATE.CommunicateInter cci = null; //通讯类型
private DATAFRAME.DataFrameInter dfi = null; //数据帧
//private Thread thread = null; //线程
byte[] dataa = null;
private int n = 18, m = 9;
private byte[] dataf = null;
public TimIntvThd(byte[] data) //构造函数
{
dataf=new byte[n];
dataf = data;
//Array.Copy(data, dataf, n);
init();
}
public override void init()
{
this.cci = COMMUNICATE.Cflag.getCtype(); //初始化通讯类
//this.dfi = new DATAFRAME.TimIntvData(); //初始化数据帧类
//dfi.setAFI();
this.thread = new Thread(new ThreadStart(this.run)); //申请线程
//throw new Exception("The method or operation is not implemented.");
}
public override void run() //线程运行的方法
{
cci.Write(dataf);
cci.Write(dataf);
}
}
}
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
/************
* 功能:采集时间间隔数据帧线程类
* **********************/
namespace LOGICDEAL.DEALTHREAD
{
public class TimIntvThd:DealThread
{
private COMMUNICATE.CommunicateInter cci = null; //通讯类型
private DATAFRAME.DataFrameInter dfi = null; //数据帧
//private Thread thread = null; //线程
byte[] dataa = null;
private int n = 18, m = 9;
private byte[] dataf = null;
public TimIntvThd(byte[] data) //构造函数
{
dataf=new byte[n];
dataf = data;
//Array.Copy(data, dataf, n);
init();
}
public override void init()
{
this.cci = COMMUNICATE.Cflag.getCtype(); //初始化通讯类
//this.dfi = new DATAFRAME.TimIntvData(); //初始化数据帧类
//dfi.setAFI();
this.thread = new Thread(new ThreadStart(this.run)); //申请线程
//throw new Exception("The method or operation is not implemented.");
}
public override void run() //线程运行的方法
{
cci.Write(dataf);
cci.Write(dataf);
}
}
}
系统可扩展的第四个地方---用户窗口公共接口(见用户窗口公共接口图),这个接口主要用来为各用户窗体需要的数据处理线程提供一个统一接口,用户窗体中可以根据需要来设计一个或多个数据处理线程,如扩展中的TimIntevForm.窗体,代码如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
/************
* 功能:采集时间间隔设置
* **********************/
namespace BUSINESSMANAGE
{
public partial class TimIntevForm : Form,DataFormInter
{
DATAACCESS.DbOperation db = null;
string ipaddr = null;
string channelnum = null;
private LOGICDEAL.DEALTHREAD.TimIntvThd tit;
private byte[] dataf=null;
public TimIntevForm(string ipaddr, string channelnum)
{
db = new DATAACCESS.DbOperation();
this.ipaddr = ipaddr;
this.channelnum = channelnum;
InitializeComponent();
}
private void btnSure_Click(object sender, EventArgs e)
{
if (txtTimintv.Text.Contains(".")) { MessageBox.Show("时间间隔不能为小数!", "确定", MessageBoxButtons.OK, MessageBoxIcon.Information); txtTimintv.Focus(); return; }
setupfram();
}
private void btnCancl_Click(object sender, EventArgs e)
{
this.Close();
}
private void setText()
{
DataTable dt = db.getData("select a.ipaddr,a.channelnum,a.reltinter,a.instinter ,a.unitnum ,a.timintv ,b.netaddress,b.netnum from t_channal a,t_node b where a.ipaddr=b.ipaddr and a.ipaddr=’" + ipaddr + "’ and a.channelnum=’"+channelnum+"’");
char[] a = new char[] { ’~’ };
txtIpaddr.Text = dt.Rows[0][0].ToString();
txtChannelnum.Text =dt.Rows[0][1].ToString();
txtunit.Text = dt.Rows[0][4].ToString();
txtTimintv.Text = dt.Rows[0][5].ToString();
string instiner = dt.Rows[0][3].ToString();
string reltinter = dt.Rows[0][2].ToString();
txtReltinters.Text = reltinter.Split(a)[0].ToString();
txtReltinterx.Text = reltinter.Split(a)[1].ToString();
txtInstinters.Text = instiner.Split(a)[0].ToString();
txtInstinterx.Text = instiner.Split(a)[1].ToString();
txtNetnum.Text = dt.Rows[0][7].ToString();
txtNetaddress.Text = dt.Rows[0][6].ToString();
}
private void setupfram()
{
dataf=new byte[18];
dataf[0] = 0xaa;
dataf[1] = 0x01;
dataf[2] = 0x0d; //数据长度
dataf[3] = 0x01; //消息类型
string daa = COMMONDEAL.DataConversion.Ten2Hex(txtTimintv.Text.ToString());
daa = COMMONDEAL.DataConversion.LenByte(daa,4);
dataf[4] = (byte)Convert.ToSByte(daa.Substring(0, 2),16); //数据sss
dataf[5] = (byte)Convert.ToSByte(daa.Substring(2, 2),16);
dataf[6] = 0x01; //保留
dataf[7] = 0x01;
dataf[8] = 0x01;
dataf[9] = 0x01;
dataf[10] = 0x01;
dataf[11] = 0x01;
dataf[12] = (byte)Convert.ToSByte(txtNetaddress.Text.ToString().Substring(0, 2),16); //网络地址
dataf[13] = (byte)Convert.ToSByte(txtNetaddress.Text.ToString().Substring(2, 2),16);
dataf[14] = (byte)Convert.ToSByte(txtNetnum.Text.ToString(),16); //网络号
dataf[15] = (byte)Convert.ToSByte(txtChannelnum.Text.ToString(),16); //通道号
int t = 0; //计算前16字节数之和,计算校验码
for (int i = 0; i < 16; i++)
{
t += dataf[i];
}
string temp = COMMONDEAL.DataConversion.LenByte(COMMONDEAL.DataConversion.Ten2Hex(t.ToString()), 4);
dataf[16] = (byte)Convert.ToSByte(temp.Substring(0, 2), 16);
dataf[17] = (byte)Convert.ToSByte(temp.Substring(2, 2), 16);
tit = new LOGICDEAL.DEALTHREAD.TimIntvThd(dataf);
tit.start();
}
private void TimIntevForm_Load(object sender, EventArgs e)
{
setText();
}
public void init(){}
public void start(){}
public void run(){}
}
}
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
/************
* 功能:采集时间间隔设置
* **********************/
namespace BUSINESSMANAGE
{
public partial class TimIntevForm : Form,DataFormInter
{
DATAACCESS.DbOperation db = null;
string ipaddr = null;
string channelnum = null;
private LOGICDEAL.DEALTHREAD.TimIntvThd tit;
private byte[] dataf=null;
public TimIntevForm(string ipaddr, string channelnum)
{
db = new DATAACCESS.DbOperation();
this.ipaddr = ipaddr;
this.channelnum = channelnum;
InitializeComponent();
}
private void btnSure_Click(object sender, EventArgs e)
{
if (txtTimintv.Text.Contains(".")) { MessageBox.Show("时间间隔不能为小数!", "确定", MessageBoxButtons.OK, MessageBoxIcon.Information); txtTimintv.Focus(); return; }
setupfram();
}
private void btnCancl_Click(object sender, EventArgs e)
{
this.Close();
}
private void setText()
{
DataTable dt = db.getData("select a.ipaddr,a.channelnum,a.reltinter,a.instinter ,a.unitnum ,a.timintv ,b.netaddress,b.netnum from t_channal a,t_node b where a.ipaddr=b.ipaddr and a.ipaddr=’" + ipaddr + "’ and a.channelnum=’"+channelnum+"’");
char[] a = new char[] { ’~’ };
txtIpaddr.Text = dt.Rows[0][0].ToString();
txtChannelnum.Text =dt.Rows[0][1].ToString();
txtunit.Text = dt.Rows[0][4].ToString();
txtTimintv.Text = dt.Rows[0][5].ToString();
string instiner = dt.Rows[0][3].ToString();
string reltinter = dt.Rows[0][2].ToString();
txtReltinters.Text = reltinter.Split(a)[0].ToString();
txtReltinterx.Text = reltinter.Split(a)[1].ToString();
txtInstinters.Text = instiner.Split(a)[0].ToString();
txtInstinterx.Text = instiner.Split(a)[1].ToString();
txtNetnum.Text = dt.Rows[0][7].ToString();
txtNetaddress.Text = dt.Rows[0][6].ToString();
}
private void setupfram()
{
dataf=new byte[18];
dataf[0] = 0xaa;
dataf[1] = 0x01;
dataf[2] = 0x0d; //数据长度
dataf[3] = 0x01; //消息类型
string daa = COMMONDEAL.DataConversion.Ten2Hex(txtTimintv.Text.ToString());
daa = COMMONDEAL.DataConversion.LenByte(daa,4);
dataf[4] = (byte)Convert.ToSByte(daa.Substring(0, 2),16); //数据sss
dataf[5] = (byte)Convert.ToSByte(daa.Substring(2, 2),16);
dataf[6] = 0x01; //保留
dataf[7] = 0x01;
dataf[8] = 0x01;
dataf[9] = 0x01;
dataf[10] = 0x01;
dataf[11] = 0x01;
dataf[12] = (byte)Convert.ToSByte(txtNetaddress.Text.ToString().Substring(0, 2),16); //网络地址
dataf[13] = (byte)Convert.ToSByte(txtNetaddress.Text.ToString().Substring(2, 2),16);
dataf[14] = (byte)Convert.ToSByte(txtNetnum.Text.ToString(),16); //网络号
dataf[15] = (byte)Convert.ToSByte(txtChannelnum.Text.ToString(),16); //通道号
int t = 0; //计算前16字节数之和,计算校验码
for (int i = 0; i < 16; i++)
{
t += dataf[i];
}
string temp = COMMONDEAL.DataConversion.LenByte(COMMONDEAL.DataConversion.Ten2Hex(t.ToString()), 4);
dataf[16] = (byte)Convert.ToSByte(temp.Substring(0, 2), 16);
dataf[17] = (byte)Convert.ToSByte(temp.Substring(2, 2), 16);
tit = new LOGICDEAL.DEALTHREAD.TimIntvThd(dataf);
tit.start();
}
private void TimIntevForm_Load(object sender, EventArgs e)
{
setText();
}
public void init(){}
public void start(){}
public void run(){}
}
}
第三部分就这样吧,设计肯定有许多漏洞,望各位多提意见了。。。
待续第四部分无线监控系统之四-------结言
版权声明:本文为开发框架文库发布内容,转载请附上原文出处连接
NewDoc C/S框架网