C#OPC数据采集(FORM)

using System;

using System.Windows.Forms;

using Opc;

using Opc.Da;

using OpcCom;

using opc_Library;

using opcTest.model;

using System.Collections.Generic;

namespace opc_collection

{

    public partial class Form1 : Form

    {

        private Opc.Da.Server m_server =null;//定义数据存取服务器

            

        private Opc.Da.Subscription subscription = null;//定义组对象(订阅者)

        private Opc.Da.SubscriptionState state = null;//定义组(订阅者)状态,相当于OPC规范中组的参数

        private Opc.IDiscovery m_discovery = new ServerEnumerator();//定义枚举基于COM服务器的接口,用来搜索所有的此类服务器。

        //时钟

        private Timer _timer = new Timer();

        //写日志记录

        write_log write_log = new write_log();

        public Form1()

        {

            InitializeComponent();

            // _timer.Interval = 2000;

            _timer.Enabled = false;

            _timer.Tick  = MainProcess;

            textBox1.Text = "192.168.1.100";

            //  button2.Enabled = false;

            //  button3.Enabled = false;

        }

         

        private void button1_Click(object sender, EventArgs e)

        {

            comboBox1.Items.Clear();

            //查询服务器

            try

            {

              string str=  Specification.COM_DA_20.ToString();

                Opc.Server[] servers = m_discovery.GetAvailableServers(Specification.COM_DA_20, textBox1.Text.ToString().Trim(), null);

                if (servers != null)

                {

                    foreach (Opc.Da.Server server in servers)

                    {

                        comboBox1.Items.Add(server.Name);

                    }

                }

               // comboBox1.SelectedIndex = 0;

            ls.Items.Add("查询服务器成功.请选择OPC进行连接");

            write_log.write_log_txt("查询服务器成功.请选择OPC进行连接");

              //  button1.Enabled = false;

                button2.Enabled = true;

            }

            catch (Exception ex)

            {

               ls.Items.Add(ex.Message);

               write_log.write_log_txt(ex.ToString());

            }

        }

        private void button2_Click(object sender, EventArgs e)

        {

            //连接

            if (button2.Text=="释放")

            {

                //结束:释放各资源

                button2.Text = "连接";

                ls.Items.Add("释放成功.不能进行读取数据,请重新连接");

                write_log.write_log_txt("释放成功.不能进行读取数据,请重新连接");

                btn_conllection.Enabled = false;

                try

                {

                    subscription.Dispose();//强制.NET资源回收站回收该subscription的所有资源。        

                    m_server.Disconnect();//断开服务器连接

                }

                catch (Exception ex)

                {

                    ls.Items.Add(ex.Message);

                    write_log.write_log_txt(ex.ToString());

                }

            }

            else

            {

                try

                {

                    Opc.Server[] servers = m_discovery.GetAvailableServers(Specification.COM_DA_20, textBox1.Text, null);

                    if (servers != null)

                    {

                        foreach (Opc.Da.Server server in servers)

                        {

                            if (String.Compare(server.Name, comboBox1.Text, true) == 0)//为true忽略大小写

                            {

                                m_server = server;//建立连接。

                                break;

                            }

                        }

                    }

                }

                catch (Exception ex)

                {

                    ls.Items.Add(ex.Message);

                    write_log.write_log_txt(ex.ToString());

                    return;

                }

                if (m_server != null)

                {

                    try

                    {

                        m_server.Connect();

                       ls.Items.Add("OPC服务器连接成功,请填写变量名称进行读取数据");

                       write_log.write_log_txt("OPC服务器连接成功.");

                     

                        button2.Text = "释放";

                        btn_conllection.Enabled = true;                        

                    }

                    catch (Exception ex)

                    {

                        ls.Items.Add(ex.Message);

                    }

                }

                else

                {

                    ls.Items.Add("连接失败,请检查IP以及服务器对象");

                    write_log.write_log_txt("连接失败,请检查IP以及服务器对象");

                }

            }

        }

        private void button3_Click(object sender, EventArgs e)

        {

         _timer.Interval =Int32.Parse(txt_time.Text.ToString().Trim());

         _timer.Enabled = true;

           // l_m.Clear();

            //   xm.xml_to_model("XML_opc.xml");

          //  l_m = xm.get_monitor_Xml_m_all();

       //     Item[] items = new Item[100];//定义数据项,即item

            int i = 0;

        /*    string daname = string.Empty;

            foreach (var e_1 in l_m)    //遍历集合

            {

             //   items[i].ClientHandle = Guid.NewGuid().ToString();//客户端给该数据项分配的句柄。

             //   items[i].ItemPath = null; //该数据项在服务器中的路径。

             //   items[i].ItemName = e_1.Opc_da;//itemName[0]; //该数据项在服务器中的名字。

             //   i  ;

                daname = e_1.Opc_da;

            }

            try

            {

                state = new Opc.Da.SubscriptionState();//组(订阅者)状态,相当于OPC规范中组的参数

                state.Name = "newGroup";//组名

                state.ServerHandle = null;//服务器给该组分配的句柄。

                state.ClientHandle = Guid.NewGuid().ToString();//客户端给该组分配的句柄。

                state.Active = true;//激活该组。

                state.UpdateRate = 100;//刷新频率为1秒。

                state.Deadband = 0;// 死区值,设为0时,服务器端该组内任何数据变化都通知组。

                state.Locale = null;//不设置地区值。

                subscription = (Opc.Da.Subscription)m_server.CreateSubscription(state);//创建组

                ls.Items.Add("1");

                string[] itemName = new string[] {""};

                ls.Items.Add("2");

                itemName[0] = daname;

                ls.Items.Add("2.1");

                Item[] items = new Item[1];//定义数据项,即item

                items[0] = new Item();

                items[0].ClientHandle = Guid.NewGuid().ToString();//客户端给该数据项分配的句柄。

                items[0].ItemPath = null; //该数据项在服务器中的路径。

                items[0].ItemName = itemName[0]; //该数据项在服务器中的名字。

                subscription.AddItems(items);

                ls.Items.Add("3");

                ItemValueResult[] values =  subscription.Read(subscription.Items);

                ls.Items.Add("4");

                ls.Items.Add(items[0].Key.ToString());

               // ls.Items.Add(values[0].Value.ToString() );

               // ls.Items.Add(values[1].Value.ToString());

                try

                {

                    

                    foreach (ItemValueResult value in values)

                    {

                       ls.Items.Add("5");

                       ls.Items.Add("成功读取变量为<"   daname   ">的数据.值为<"   value.Value.ToString()   ">");

                    }

            /*        if (values[0].Quality.Equals(Opc.Da.Quality.Good))

                    {                       

                        // textBox3.Text = values[0].Value.ToString();

                        ls.Items.Add("成功读取变量为<"   daname   ">的数据.值为<"   values[0].Value.ToString()   ">");

                    }

             * */

       /*         }

                catch (Exception e2)

                {

                    ls.Items.Add("e2:" e2.ToString());

                }

                subscription.RemoveItems(subscription.Items);

                m_server.CancelSubscription(subscription);//m_server前文已说明,通知服务器要求删除组。

            }

            catch (Exception ex)

            {

                ls.Items.Add(ex.Message);

            }

*/

        }

     //Form界面控制部分 

     #region Form_Monitor   

        private void alert(string msg)

        {

            MessageBox.Show(msg, "系统提示", MessageBoxButtons.OK, MessageBoxIcon.Information);

        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)

        {

            if (e.CloseReason == CloseReason.UserClosing)//当用户点击窗体右上角X按钮或(Alt   F4)时 发生           

            {

                e.Cancel = true;

                this.ShowInTaskbar = false;

                this.notifyIcon1.Icon = this.Icon;

                this.Hide();

            }

        }

        private void notifyIcon1_MouseClick(object sender, MouseEventArgs e)

        {

            if (e.Button == MouseButtons.Right)

            {

                mymenu.Show(System.Windows.Forms.Cursor.Position.X, System.Windows.Forms.Cursor.Position.Y);

                mymenu.Show();

            }

            if (e.Button == MouseButtons.Left)

            {

                this.Visible = true;

                mymenu.Hide();

                this.Icon = Resource1._20151104082741597_easyicon_net_256;

                this.WindowState = FormWindowState.Normal;

            }        

        }

        private void mymenu_Click(object sender, EventArgs e)

        {

        }

        private void mymenu_Opening(object sender, System.ComponentModel.CancelEventArgs e)

        {

        }

        private void mymenu_child_Click(object sender, EventArgs e)

        {

            Application.Exit();  

        }

        private void Form1_MinimumSizeChanged(object sender, EventArgs e)

        {

            if (this.WindowState == FormWindowState.Normal && this.Visible == true)

            {

                this.notifyIcon1.Visible = true;//在通知区显示Form的Icon

                this.WindowState = FormWindowState.Minimized;

                this.Visible = false;

                this.ShowInTaskbar = false;//使Form不在任务栏上显示

            }

        }

  #endregion

        private void btn_stop_Click(object sender, EventArgs e)

        {

            _timer.Enabled = false;

            ls.Items.Clear();

        

        //重新加载OPC点位

        List<monitor> l_m = new List<monitor>();

        xml_to_model xm = new xml_to_model("XML_opc.xml");

        string daname = string.Empty;

        public void MainProcess(object sender, EventArgs e)

        {

            l_m.Clear();

         //   xm.xml_to_model("XML_opc.xml");

            l_m=xm.get_monitor_Xml_m_all();

       //     Item[] items = new Item[100];//定义数据项,即item

        //    int i = 0;

           

        //    foreach (var e_1 in l_m)  //遍历集合

         //   {

            foreach (var e_1 in l_m)    //遍历集合

            {

                daname = e_1.Opc_da;

                try

                {

                    state = new Opc.Da.SubscriptionState();//组(订阅者)状态,相当于OPC规范中组的参数

                    state.Name = "newGroup";//组名

                    state.ServerHandle = null;//服务器给该组分配的句柄。

                    state.ClientHandle = Guid.NewGuid().ToString();//客户端给该组分配的句柄。

                    state.Active = true;//激活该组。

                    state.UpdateRate = 100;//刷新频率为1秒。

                    state.Deadband = 0;// 死区值,设为0时,服务器端该组内任何数据变化都通知组。

                    state.Locale = null;//不设置地区值。

                    subscription = (Opc.Da.Subscription)m_server.CreateSubscription(state);//创建组

                    ls.Items.Add("1");

                    string[] itemName = new string[] { "" };

                    ls.Items.Add("2");

                    itemName[0] = daname;

                    ls.Items.Add("2.1");

                    Item[] items = new Item[1];//定义数据项,即item

                    items[0] = new Item();

                    items[0].ClientHandle = Guid.NewGuid().ToString();//客户端给该数据项分配的句柄。

                    items[0].ItemPath = null; //该数据项在服务器中的路径。

                    items[0].ItemName = itemName[0]; //该数据项在服务器中的名字。

                    subscription.AddItems(items);

                    ls.Items.Add("3");

                    ItemValueResult[] values = subscription.Read(subscription.Items);

                    ls.Items.Add("4");

                    ls.Items.Add(items[0].Key.ToString());

                    // ls.Items.Add(values[0].Value.ToString() );

                    // ls.Items.Add(values[1].Value.ToString());

                    try

                    {

                       // foreach (ItemValueResult value in values)

                      //  {

                            ls.Items.Add("5");

                            #region

                            //插入DB OPCMAP

                            Db_Access dba = new Db_Access();

                            //判断MAP表里是否有该DA

                            ReadXml readxml = new ReadXml();

                            string[] db_name_insert = readxml.getXml_node("2", "db_name", "XML_db.xml");

                            string db_name = db_name_insert[0];

                            string map_isexists = @"select count(opc_id) from";

                            map_isexists = map_isexists   " "   "[".Trim()   db_name.Trim()   "]".Trim()   ".".Trim()   "[dbo]".Trim()   ".".Trim()   "[tb_opc_map]";

                            write_log.write_log_txt(map_isexists);

                            if (dba.get_sql_int("2", map_isexists) == 0)

                            {

                                string map_insert = @"INSERT INTO ";

                                map_insert = map_insert   " "   "[".Trim()   db_name.Trim()   "]".Trim()   ".".Trim()   "[dbo]".Trim()   ".".Trim()   "[tb_opc_map]([opc_id]"

                                " ,[opc_da],[opc_name],[opc_type],[c_flag])"   " "   "select "   "‘"   "1"   "‘,"   "‘"   e_1.Opc_da.Trim()   "‘,"   "‘"   e_1.Opc_name.Trim()   "‘"   ","   "‘"   e_1.Opc_type.Trim()   "‘,"   "‘"   e_1.C_flag.Trim()   "‘";

                                write_log.write_log_txt(map_insert);

                                if (dba.get_sql_opreate("2", map_insert) == "1")

                                {

                                    //获取插入的OPC ID

                                    string opc_id_sql = @"select top 1 opc_id from";

                                    opc_id_sql = opc_id_sql   " "   "[".Trim()   db_name.Trim()   "]".Trim()   ".".Trim()   "[dbo]".Trim()   ".".Trim()   "[tb_opc_map] where opc_name=‘"   e_1.Opc_name.Trim()   "‘";

                                    write_log.write_log_txt(opc_id_sql );

                                    string opc_id = dba.get_sql_opreate("2", opc_id_sql);

                                    string opc_insert = @"INSERT INTO ";

                                    opc_insert = opc_insert   " "   "[".Trim()   db_name.Trim()   "]".Trim()   ".".Trim()   "[dbo]".Trim()   ".".Trim()   "[tb_opc]([opc_id]"

                                          ",opc_value,collection_time)"   "select "   "‘"   opc_id.Trim()   "‘,"   "‘"  "0.01"  "‘,"   "‘"   DateTime.Now.ToString()   "‘";

                                //  opc_insert = opc_insert   " "   "[".Trim()   db_name.Trim()   "]".Trim()   ".".Trim()   "[dbo]".Trim()   ".".Trim()   "[tb_opc]([opc_id]"

                                //          ",opc_value,collection_time)"   "select "   "‘"   opc_id.Trim()   "‘,"   "‘"  values[0].Value.ToString().Trim()   "‘,"   "‘"   DateTime.Now.ToString()   "‘";

                                    write_log.write_log_txt(opc_insert );

                                    if (dba.get_sql_opreate("2", opc_insert) == "0")

                                    {

                                        write_log.write_log_txt("插入OPC数据表失败,请检查程序。");

                                    }

                                }

                                else

                                {

                                    write_log.write_log_txt("插入OPC配置表失败,请检查程序。");

                                }

                            }

                            if (dba.get_sql_int("2", map_isexists) > 0)

                            {

                                //获取插入的OPC ID

                                string opc_id_sql = @"select count(opc_id) from";

                                opc_id_sql = opc_id_sql   " "   "[".Trim()   db_name.Trim()   "]".Trim()   ".".Trim()   "[dbo]".Trim()   ".".Trim()   "[tb_opc_map] where opc_name=‘"   e_1.Opc_name.Trim()   "‘";

                                write_log.write_log_txt(">0:"   opc_id_sql);

                               // string opc_id = dba.get_sql_opreate("2", opc_id_sql);

                                int opc_id_flag = dba.get_sql_int("2", opc_id_sql);

                                string opc_id = string.Empty;

                                if (opc_id_flag > 0)

                                {

                                     string opc_id_sql_1 = @"select top 1 opc_id from";

                                     opc_id_sql_1 = opc_id_sql_1   " "   "[".Trim()   db_name.Trim()   "]".Trim()   ".".Trim()   "[dbo]".Trim()   ".".Trim()   "[tb_opc_map] where opc_name=‘"   e_1.Opc_name.Trim()   "‘";

                                    opc_id = dba.get_sql_str("2", opc_id_sql_1);

                                }

                                if (opc_id_flag == 0)

                                {

                                    string opc_id_sql_1 = @"select max(opc_id) 1 from";

                                    opc_id_sql_1 = opc_id_sql_1   " "   "[".Trim()   db_name.Trim()   "]".Trim()   ".".Trim()   "[dbo]".Trim()   ".".Trim()   "[tb_opc_map]";

                                  string   opc_id_map= dba.get_sql_str("2", opc_id_sql_1);

                                    string map_insert = @"INSERT INTO ";

                                    map_insert = map_insert   " "   "[".Trim()   db_name.Trim()   "]".Trim()   ".".Trim()   "[dbo]".Trim()   ".".Trim()   "[tb_opc_map]([opc_id]"

                                    " ,[opc_da],[opc_name],[opc_type],[c_flag])"   " "   "select "   "‘"   opc_id_map   "‘,"   "‘"   e_1.Opc_da.Trim()   "‘,"   "‘"   e_1.Opc_name.Trim()   "‘"   ","   "‘"   e_1.Opc_type.Trim()   "‘,"   "‘"   e_1.C_flag.Trim()   "‘";

                                    dba.get_sql_opreate("2",map_insert);

                                    string opc_id_sql_2 = @"select top 1 opc_id from";

                                    opc_id_sql_2 = opc_id_sql_2   " "   "[".Trim()   db_name.Trim()   "]".Trim()   ".".Trim()   "[dbo]".Trim()   ".".Trim()   "[tb_opc_map] where opc_name=‘"   e_1.Opc_name.Trim()   "‘";

                                    opc_id = dba.get_sql_str("2", opc_id_sql_2);

                                }

                                string opc_insert = @"INSERT INTO ";

                                opc_insert = opc_insert   " "   "[".Trim()   db_name.Trim()   "]".Trim()   ".".Trim()   "[dbo]".Trim()   ".".Trim()   "[tb_opc]([opc_id]"

                                      ",opc_value,collection_time)"   "select "   "‘"   opc_id.Trim()   "‘,"   "‘"   "0.00"  "‘,"   "‘"   DateTime.Now.ToString()   "‘";

                            //    opc_insert = opc_insert   " "   "[".Trim()   db_name.Trim()   "]".Trim()   ".".Trim()   "[dbo]".Trim()   ".".Trim()   "[tb_opc]([opc_id]"

                             //     ",opc_value,collection_time)"   "select "   "‘"   opc_id.Trim()   "‘,"   "‘"   values[0].Value.ToString().Trim()   "‘,"   "‘"   DateTime.Now.ToString()   "‘";

                       

                                write_log.write_log_txt(">0:"   opc_insert);

                                if (dba.get_sql_opreate("2", opc_insert) == "0")

                                {

                                    write_log.write_log_txt("插入OPC数据表失败,请检查程序。");

                                }

                            }

                            #endregion

                            ls.Items.Add(new ListViewItem(new string[] { e_1.Opc_da.Trim(), e_1.Opc_name.Trim(), values[0].Value.ToString().Trim(), DateTime.Now.ToString() }));

                            write_log.write_log_txt(e_1.Opc_da   "  "   e_1.Opc_name   "  "   values[0].Value.ToString()   "  "   DateTime.Now.ToString());

                    //    }

                        /*        if (values[0].Quality.Equals(Opc.Da.Quality.Good))

                                {

                       

                                    // textBox3.Text = values[0].Value.ToString();

                                    ls.Items.Add("成功读取变量为<"   daname   ">的数据.值为<"   values[0].Value.ToString()   ">");

                                }

                         * */

                    }

                    catch (Exception e2)

                    {

                        ls.Items.Add("e2:"   e2.ToString());

                    }

                    subscription.RemoveItems(subscription.Items);

                    m_server.CancelSubscription(subscription);//m_server前文已说明,通知服务器要求删除组。

                }

                catch (Exception ex)

                {

                    ls.Items.Add(ex.Message);

                }

            }                

            }        

    }

}

原文地址:https://www.cnblogs.com/keepdoit/p/11970650.html

时间: 2024-10-08 08:34:13

C#OPC数据采集(FORM)的相关文章

OPC客户端开发问题总结

环境准备 采用MatrikonOPC做模拟服务器,注册 OPCDAAuto.dll组件 引用 Interop.OPCAutomation.dll组件.开始开发. 1..new OPCServer()--Connect() 2.映射组注册组内标签,监听 组的DataChange事件更新数据. 遇到的问题. 0.同一个Connect注册过多的组或者标签也会报错(一个客户端可以发起多个连接) 1.OPC同一个组内大量标签会有更新数据非常慢的问题,或者会引起OPCServer崩溃(遇到过30+就崩溃的)

OPC通信原理在数采中的应用

OPC通信原理在数采中的应用 OPC是Object Linking and Embedding(OLE)for Process Control的缩写,它是微软公司的对象链接和嵌入技术在过程控制方面的应用.OPC以OLE/COM/DCOM技术为基础,采用客户/服务器模式,为工业自动化软件面向对象的开发提供了统一的标准,这个标准定义了应用Microsoft操作系统在基于PC的客户机之间交换自动化实时数据的方法. 在OPC数据存取规范中,一个OPC的数据存取服务器中包括几类对象(OPC Server)

实时数据库简介和比较

实时数据库是数据库系统发展的一个分支,它适用于处理不断更新的快速变化的数据及具有时间限制的事务处理.实时数据库技术是实时系统和数据库技术相结合的产物,实时数据库系统的主要内容包括: 实时数据库模型: 实时事务调度:包括并发控制.冲突解决.死锁等内容: 容错性与错误恢复: 内存组织与管理: 访问准入控制: I/O与磁盘调度: 主内存数据库系统: 不精确计算问题: 放松的可串行化问题: 实时SQL: 实时事务的可预测性: 研究现状与发展目前在国内比较流性的国外实时数据库产品有Wonderware公司

实时数据库简介

http://blog.csdn.net/hzhsan/article/details/9384885 1.前言 一提到数据库,大家肯定会想到SQL Server.Oracle等关系型数据库.实际上,数据库的种类非常多,在计算机发展的历史上,存在着多种类型的数据库.早期,关系型数据库与层次型数据库.网络型数据库并驾齐驱,但关系型数据库依靠其描述简单.实现容易等特点,在竞争中取得了胜利,在上世纪90年代初期,从Foxpro.Access到Oracle.Informix.SyBase.SQL ser

SharpNodeSettings项目,可配置的数据采集,统一的工业数据网关,OPC UA服务器开发,PLC数据发布到自身内存,redis,opc ua,以及数据可视化开发

本项目隶属于 HslCommunication 项目的SDK套件,如果不清楚HslCommunication组件的话,可以先了解那个项目,源代码地址:https://github.com/dathlin/HslCommunication 本项目源代码地址:https://github.com/dathlin/SharpNodeSettings 本项目的主要实现的功能主要有2个: 实现单个设备信息的可配置,可存储,采用一个相对标准的Xml存储机制实现,适用的场景是:如果你有20个西门子PLC(种类

数据采集之Web端上传文件到Hadoop HDFS

前言 最近在公司接到一个任务,是关于数据采集方面的. 需求主要有3个: 通过web端上传文件到HDFS; 通过日志采集的方式导入到HDFS; 将数据库DB的表数据导入到HDFS. 正好最近都有在这方面做知识储备.正所谓养兵千日,用兵一时啊.学习到的东西只有应用到真实的环境中才有意义不是么. 环境 这里只做模拟环境,而不是真实的线上环境,所以也很简单,如果要使用的话还需要优化优化. OS Debian 8.7 Hadoop 2.6.5 SpringBoot 1.5.1.RELEASE 说明一下,这

《连载 | 物联网框架ServerSuperIO教程》- 18.集成OPC Client,及使用步骤。附:3.5 发布与更新说明。

1.C#跨平台物联网通讯框架ServerSuperIO(SSIO)介绍 <连载 | 物联网框架ServerSuperIO教程>1.4种通讯模式机制. <连载 | 物联网框架ServerSuperIO教程>2.服务实例的配置参数说明 <连载 | 物联网框架ServerSuperIO教程>- 3.设备驱动介绍 <连载 | 物联网框架ServerSuperIO教程>-4.如开发一套设备驱动,同时支持串口和网络通讯. <连载 | 物联网框架ServerSupe

C#工业物联网和集成系统解决方案的技术路线(数据源、数据采集、数据上传与接收、ActiveMQ、Mongodb、WebApi、手机App)

目       录 工业物联网和集成系统解决方案的技术路线... 1 前言... 1 第一章           系统架构... 3 1.1           硬件构架图... 3 1.2           组件构架图... 4 第二章           技术选型与介绍... 5 2.1           开发环境... 5 2.2           数据源... 5 2.3           数据采集... 5 2.4           数据上传服务... 6 2.5      

使用OPC的方式去连接PLC进行AB SLC-5_04数据的采集

1.  必备软件 Rslinx classic 2.57 .net framework 2.0 VS2013 OS: win7 enterprise x64 2.  软件安装 2.1.安装RSlinx,安装时选择xp3兼容模式. 2.2.安装后启动RsLinx,对PLC进行配置.首先,建立驱动,驱动类型选择“EnterNet device”,将PLC设备的IP地址输入,如下图: 2.3.正确配置后,结果如下图, 在图中“192.168.1.254”的节点上,鼠标右键,可以看到datamonito