Exemple #1
0
        /// <summary>
        /// 把更新的OPC ITEM数据保存到全局容器以供网络服务线程访问
        /// </summary>
        /// <param name="values">更新的结果集</param>
        private static void Controller_DataChange(Dictionary <string, string> values)
        {
            Hashtable hashtable = new Hashtable();

            foreach (string key in values.Keys)
            {
                hashtable.Add(key, values[key]);
            }

            log.Debug("接收到KEPWARE的更新数据");
            foreach (string key in ValuesContainer.Values.Keys)
            {
                if (ValuesContainer.Values[key].ToString() != hashtable[key].ToString())
                {
                    ValuesContainer.LastSyncs[key] = DateTime.Now;

                    if (_debug)
                    {
                        log.Debug(key + ": " + ValuesContainer.Values[key] + "=>" + hashtable[key]);
                    }
                }
            }

            foreach (string key in hashtable.Keys)
            {
                ValuesContainer.Values[key] = hashtable[key].ToString();
            }

            if (_persistence)
            {
                ValuesContainer.Persist(configFile.Replace(".xml", ".opc"));
            }
        }
Exemple #2
0
        /// <summary>
        /// 在KEPWARE服务器上设置订阅
        /// </summary>
        /// <param name="server">KEPWARE服务器名称</param>
        /// <param name="channelName">订阅的通道</param>
        /// <param name="deviceName">订阅的设备</param>
        /// <param name="blockNames">要订阅的ITEM名称集</param>
        /// <param name="blockTypes">要订阅的ITEM数据类型集</param>
        private static void InitializeSubscription(string server, string channelName, string deviceName, List <string> blockNames, Hashtable blockTypes)
        {
            // 重新创建KEPWARE控制器对象
            if (controller.Connected)
            {
                controller.Disconnect();
                log.Info("已从KEPWARE服务断开");
                controller = null;
                controller = new KEPWareController();
                controller.BadBlockDetected += Controller_BadBlockDetected;
            }

            // 连接到OPC服务
            string serverName = server;

            if (controller.Connect(serverName))
            {
                log.Info("已连接到KEPWARE服务" + serverName);
            }
            else
            {
                log.Error("连接失败!服务器将退出!");
                Environment.Exit(-1);
            }


            // 设置OPC订阅信息
            controller.ChannelName = channelName;
            log.Info("已将通道名称设置为 " + controller.ChannelName);
            controller.DeviceName = deviceName;
            log.Info("已将设备名称设置为 " + controller.DeviceName);
            controller.AddItems(blockNames.ToArray());
            controller.DataChange += Controller_DataChange;

            // 初始化全局结果集
            Hashtable hashtable = new Hashtable();

            foreach (string key in blockNames)
            {
                hashtable.Add(key, "");
            }
            ValuesContainer.Values           = hashtable;
            ValuesContainer.Types            = blockTypes;
            ValuesContainer.Qualities        = _qualities;
            ValuesContainer.ReadCounts       = _itemReadCount;
            ValuesContainer.WriteCounts      = _itemUpdateCount;
            ValuesContainer.LastUpdates      = _itemLastUpdate;
            ValuesContainer.LastSyncs        = _itemLastSync;
            ValuesContainer.ItemDescriptions = _itemDesc;

            string persistFile = configFile.Replace(".xml", ".opc");

            // 尝试读取之前保存的OPC状态
            try
            {
                // 检查服务器是否启用持久化
                if (_persistence)
                {
                    ValuesContainer.Load(persistFile, true);
                    log.Info("已恢复持久化文件 " + persistFile);
                }
            }
            catch (Exception ex)
            {
                log.Error("读取持久化文件 " + persistFile + " 出错:" + ex.Message);
            }

            // 启动监听服务
            try
            {
                controller.Subscribe();
                log.Info("OPC监听服务已启动");
            }
            catch (Exception ex)
            {
                log.Info("无法启动监听服务!" + ex.Message);
                controller.Disconnect();
                Environment.Exit(-1);
            }
        }
Exemple #3
0
        /// <summary>
        /// 处理TCP监听线程返回的ITEM更新事件
        /// </summary>
        /// <param name="blockName"></param>
        /// <param name="newValue"></param>
        public static void Listener_OPCItemUpdated(string blockName, string newValue, string clientType)
        {
            if (!ValuesContainer.Values.ContainsKey(blockName))
            {
                log.Error("OPC服务器未配置此OPCItem " + blockName);
                return;
            }

            string type = ValuesContainer.Types[blockName].ToString();

            while (_reloading)
            {
                System.Threading.Thread.Sleep(20);
            }
            try
            {
                bool writeStatus = false;
                log.Info("正在更新OPCItem " + blockName + ":" + type + "=" + newValue);
                switch (type)
                {
                case "BOOL":
                    writeStatus = controller.SetValue(blockName, bool.Parse(newValue));
                    break;

                case "BYTE":
                    writeStatus = controller.SetValue(blockName, byte.Parse(newValue));
                    break;

                case "CHAR":
                    writeStatus = controller.SetValue(blockName, char.Parse(newValue));
                    break;

                case "WORD":
                    writeStatus = controller.SetValue(blockName, short.Parse(newValue));
                    break;

                case "LONG":
                    writeStatus = controller.SetValue(blockName, int.Parse(newValue));
                    break;

                case "DWORD":
                    writeStatus = controller.SetValue(blockName, int.Parse(newValue));
                    break;

                case "STRING":
                    writeStatus = controller.SetValue(blockName, newValue);
                    break;
                }

                if (writeStatus)
                {
                    ValuesContainer.Values[blockName]      = newValue;
                    ValuesContainer.LastUpdates[blockName] = DateTime.Now;
                    ValuesContainer.WriteCounts[blockName] = (int)ValuesContainer.WriteCounts[blockName] + 1;
                    if (_persistence)
                    {
                        ValuesContainer.Persist(configFile.Replace(".xml", ".opc"));
                    }
                }
                else
                {
                    log.Error("写入OPCITEM " + blockName + ":" + type + " 失败,更改已经被取消");
                }
            }
            catch (Exception ex)
            {
                log.Error("写入OPCITEM " + blockName + ":" + type + " 失败: " + ex.Message);
            }
        }
Exemple #4
0
        /// <summary>
        /// 主程序
        /// </summary>
        /// <param name="args">命令行参数列表</param>
        static void Main(string[] args)
        {
            // 处理所有未捕获的异常
            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;


            // 获取服务器和连接器版本
            Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();

            _version = assembly.GetName().Version.ToString();
            Assembly assembly1 = Assembly.GetAssembly(typeof(KEPWareController));

            _version1 = assembly1.GetName().Version.ToString();

            // 让log4net监控配置文件的变化
            FileInfo appConfigInfo = new FileInfo(_appConfig);

            log4net.Config.XmlConfigurator.ConfigureAndWatch(appConfigInfo);

            Console.WriteLine("****************************************************************");
            Console.WriteLine("OPC代理服务器");
            Console.WriteLine("服务器版本:" + _version);
            Console.WriteLine("Kepware连接器版本:" + _version1);
            Console.WriteLine("GNU GENERAL PUBLIC LICENSE V3");
            Console.WriteLine("****************************************************************");
            Console.WriteLine("");

            // 检查命令行参数,输出用法信息
            if (args.Length == 0)
            {
                Console.WriteLine(@"
错误:未指定有效的启动参数,正确的使用方法如下: opcservice -c <OPC配置文件名.xml> [-d] [-s]
-c <OPC配置文件名> 必须参数,指定服务器加载的配置文件定义
-d 调试模式,添加此参数服务器将输出更详细的日志
-s 服务模式,添加此参数服务器已静默方式启动,将关闭控制台及日志输出(文件日志不受影响)
                ");
                Console.ReadKey();
                Environment.Exit(0);
            }

            // 处理命令行参数
            for (int n = 0; n < args.Length; n++)
            {
                // 处理要加载的配置文件名
                if (args[n] == "-c" || args[n] == "/c")
                {
                    configFile = args[n + 1];
                }

                // 是否启用debug模式(将输出更详细的调试日志)
                if (args[n] == "-d" || args[n] == "/d")
                {
                    _debug = true;
                }

                // 是否启用服务模式 (没有控制台)
                if (args[n] == "-s" || args[n] == "/c")
                {
                    _daemon = true;
                }
            }

            // 服务模式重定向控制台输出到标准错误
            // 并且取消控制台窗口
            if (_daemon)
            {
                Console.WriteLine("\n\r请点击关闭按钮关闭此控制台窗口进入无人值守模式!");
                Console.SetOut(new StreamWriter(Console.OpenStandardError(), System.Text.Encoding.UTF8));
                FreeConsole();
            }



            List <string> blockNames     = new List <string>();
            Hashtable     blockTypes     = new Hashtable();
            Hashtable     blockQualities = new Hashtable();

            // 从配置文件中加载监听设置
            if (!LoadConfiguration(configFile, ref _host, ref _server, ref blockTypes, ref blockNames, ref _channelName, ref _deviceName, ref _port, ref _persistence, ref _qualities, ref _clientTimeout, ref _itemLastUpdate, ref _itemReadCount, ref _itemUpdateCount, ref _itemLastSync, ref _itemDesc))
            {
                log.Error("配置文件读取错误!请检查文件格式再试!");
                Environment.Exit(-1);
            }

            // 服务器启动
            log.Info("服务器正在启动");

            // 查找OPC服务
            log.Info("开始查找本机安装的KEPWARE服务");
            List <string> servers = controller.FindServers();

            if (servers.Count < 1)
            {
                log.Error("没有发现本机安装了可用的OPC服务器,服务器将退出");
                Environment.Exit(-1);
            }

            // 检查本机是否存在配置文件中指定的KEPWARE服务器
            bool found = false;

            foreach (string s in servers)
            {
                if (s == _server)
                {
                    found = true;
                }
            }

            if (!found)
            {
                log.Error("没有找到配置中指定的KEPWARE服务器 " + _server);
                Environment.Exit(-1);
            }


            // 开始订阅OPC更新
            log.Info("检测到OPC服务器 " + _server + ", 正在连接");
            InitializeSubscription(_server, _channelName, _deviceName, blockNames, blockTypes);

            // 启动网络组件
            _listener = new TCPListener(_port, _clientTimeout);
            _listener.OPCItemUpdated += Listener_OPCItemUpdated;
            _listener.Start();

            log.Info("网络服务组件已启动");

            // 服务模式不使用命令行界面
            if (_daemon)
            {
                Thread.Sleep(Timeout.Infinite);
            }

            #region 命令行控制界面
            Console.WriteLine("");
            Console.WriteLine("请输入命令(输入help或者?查看可用命令列表):");
            while (true)
            {
                Console.Write(configFile.ToUpper().Replace(".XML", "") + "> ");
                string cmd2 = Console.ReadLine();
                string cmd  = cmd2.ToLower();

                // 命令解释器
                if (cmd == "?" || cmd == "help")
                {
                    ShowHelp();
                }
                else if (cmd == "reload")
                {
                    Console.Write("确定要从配置文件中重新加载配置吗?(y/n):");
                    if (Console.ReadLine().ToLower() == "y")
                    {
                        _reloading = true;
                        LoadConfiguration(configFile, ref _host, ref _server, ref blockTypes, ref blockNames, ref _channelName, ref _deviceName, ref _port, ref _persistence, ref _qualities, ref _clientTimeout, ref _itemLastUpdate, ref _itemReadCount, ref _itemUpdateCount, ref _itemLastSync, ref _itemDesc);
                        InitializeSubscription(_server, _channelName, _deviceName, blockNames, blockTypes);
                        _reloading = false;
                        Console.WriteLine("设置已重新加载!(请注意如果修改了监听端口号,必须关闭并重启服务程序!)");
                    }
                }
                else if (cmd == "exit")
                {
                    Console.Write("确定要退出OPC服务器吗?生产线和MES的通信将完全中断!(y/n):");
                    if (Console.ReadLine().ToLower() == "y")
                    {
                        _listener.Terminate();
                        controller.Disconnect();
                        Console.Write("服务已关闭,按任意键退出 ...");
                        Console.ReadKey();
                        Environment.Exit(0);
                    }
                }
                else if (cmd == "show")
                {
                    Console.WriteLine();
                    ShowTagList();
                    Console.WriteLine();
                }
                else if (cmd.StartsWith("set"))
                {
                    if (cmd.Split(' ').Length < 2)
                    {
                        Console.WriteLine("命令语法错误! 输入help查看用法");
                        continue;
                    }
                    try
                    {
                        string blockName  = cmd2.Replace("=", " ").Split(' ')[1];
                        string blockValue = cmd2.Replace("=", " ").Split(' ')[2];
                        Console.Write("确定要将OPCITEM " + blockName + " 的值更改为 " + blockValue + " 吗?(y/n):");
                        if (Console.ReadLine().ToLower() == "y")
                        {
                            Listener_OPCItemUpdated(blockName, blockValue, "STRING");
                        }
                    }
                    catch
                    {
                        Console.WriteLine("命令语法错误! 输入help查看用法");
                        continue;
                    }
                }
                else if (cmd == "save")
                {
                    string filename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, DateTime.Now.ToString("yyyyMMddHHmmss") + ".opc");
                    ValuesContainer.Persist(filename);
                    Console.WriteLine("文件已保存到 " + filename);
                }
                else if (cmd.StartsWith("load"))
                {
                    if (cmd.Split(' ').Length < 2)
                    {
                        Console.WriteLine("命令语法错误! 输入help查看用法");
                        continue;
                    }
                    string filename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, cmd2.Split(' ')[1]);
                    if (File.Exists(filename))
                    {
                        ValuesContainer.Load(filename, true);
                        Console.WriteLine("OPC文件已加载并应用到所有的Item");
                    }
                    else
                    {
                        Console.WriteLine("指定的文件 " + filename + " 不存在!");
                    }
                }
                else if (cmd == "status")
                {
                    Console.WriteLine("");
                    TimeSpan span = DateTime.Now.Subtract(_start);
                    Console.WriteLine("服务器版本:" + _version);
                    Console.WriteLine("KEPWARE连接器版本:" + _version1);
                    Console.WriteLine("服务器地址:" + GetIPAddress() + ":" + _port);
                    Console.WriteLine("配置文件:" + configFile);
                    Console.WriteLine("通道名称:" + _channelName);
                    Console.WriteLine("设备名称:" + _deviceName);
                    Console.WriteLine("Kepware主机:" + _host);
                    Console.WriteLine("Kepware服务:" + _server);
                    Console.WriteLine("持久化存储:" + _persistence.ToString());
                    Console.WriteLine("客户端无通信超时:" + _clientTimeout + " 秒");
                    Console.WriteLine("OPC组名称:" + controller.GroupName);
                    Console.WriteLine("已正常运行:" + span.Days + "天" + span.Hours + "小时" + span.Minutes + "分钟" + span.Seconds + "秒");
                    Console.WriteLine("当连接客户端:" + _listener.Clients.Count + "个");
                    for (int n = 0; n < _listener.Clients.Count; n++)
                    {
                        TimeSpan heartbeatTs = DateTime.Now.Subtract(_listener.Clients[n].LastHeartbeat);
                        string   heartbeat   = heartbeatTs.Minutes + "分" + heartbeatTs.Seconds + "秒" + heartbeatTs.Milliseconds + "毫秒";
                        Console.WriteLine(_listener.Clients[n].IPAddress + " - 上次通信:" + heartbeat);
                    }
                    Console.WriteLine("");
                }
                else if (cmd == "clear")
                {
                    Console.Clear();
                }
                else if (cmd == "monitor")
                {
                    // 启动监视器
                    _monitor = new Thread(new ThreadStart(MonitorHandler));
                    _monitor.IsBackground = true;
                    _monitor.Start();

                    // 控制刷新速度
                    bool quit = false;
                    while (!quit)
                    {
                        ConsoleKeyInfo info = Console.ReadKey();
                        if (info.KeyChar == '=' || info.KeyChar == '+')
                        {
                            // 增加刷新速度
                            if (_refreshRate >= 150)
                            {
                                _refreshRate -= 100;
                            }
                            else
                            {
                                if (_refreshRate > 20)
                                {
                                    _refreshRate -= 20;
                                }
                            }
                        }
                        else if (info.KeyChar == '-')
                        {
                            // 降低刷新速度
                            if (_refreshRate < 150)
                            {
                                _refreshRate += 20;
                            }
                            else
                            {
                                _refreshRate += 100;
                            }
                        }
                        else if (info.KeyChar == 'c' || info.KeyChar == 'C')
                        {
                            // 退出监视器
                            quit = true;
                            Console.Clear();
                        }
                    }

                    _monitor.Abort();
                    _monitor = null;
                }
                else if (cmd == "")
                {
                }
                else
                {
                    ShowHelp();
                }
            }
            #endregion
        }