zoukankan      html  css  js  c++  java
  • 监听端口守护进程

    场景:公司写的程序老是崩掉,各种改版无果,遂写一个守护进程来监听该程序,如果崩掉,就自动重启。


    1. 添加进程管理类 ProcessHelper

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Guard
    {
        public class ProcessHelper
        {
            /// <summary>
            /// 查看进程是否存在
            /// </summary>
            /// <param name="name">进程名称</param>
            /// <returns></returns>
            public static bool Exist(string name)
            {
                return Process.GetProcessesByName(name).Length > 0;
            }
    
            /// <summary>
            /// 开启进程
            /// </summary>
            /// <param name="path">进程所在物理路径</param>
            /// <returns></returns>
            public static void Start(string path)
            {
                Process m_Process = new Process();
                m_Process.StartInfo.FileName = path;
                //开启新的窗体
                m_Process.StartInfo.UseShellExecute = true;
                m_Process.Start();
             
            }
    
            /// <summary>
            /// 关闭进程
            /// </summary>
            /// <param name="name">进程名称</param>
            /// <returns></returns>
            public static void Stop(string name)
            {
                Process proc = Process.GetProcessesByName(name).FirstOrDefault();
                if (proc != null)
                    proc.Kill();
            }
        }
    }

    2. 添加配置文件 App.config

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
        <appSettings>
        <!--守护间隔时间-->
        <add key="second" value="10"/>
            <!--守护程序端口-->
            <add key="port" value="104"/>
            <!--守护程序路径-->
            <add key="path" value="D:项目文件某某系统XXXXXinDebugXXXXXXXXXX.exe"/>
        </appSettings>
    </configuration>

    3. 在类型库里面添加引用 System.configuration,方便获取配置文件自定义的值

    4. 实现代码

    using System;
    using System.Collections.Generic;
    using System.Configuration;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Net.NetworkInformation;
    using System.Text;
    using System.Threading;
    
    namespace Guard
    {
        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    int second = Convert.ToInt32(ConfigurationManager.AppSettings["second"]);
                    int port = Convert.ToInt32(ConfigurationManager.AppSettings["port"]);
                    string path = ConfigurationManager.AppSettings["path"];
    
                    while (true)
                    {
                        Console.WriteLine("Port: " + port + " status: " + (PortInUse(port) ? "存在" : "不存在"));
                        if (!PortInUse(port)) //如果监听的端口不存在,就启动对应的程序
                        {
                            WriteLog("启动端口" + port + "的程序");
                            ProcessHelper.Start(path);
                        }
                        Thread.Sleep(second * 1000);
                    }
                }
                catch (Exception ex)
                {
                    WriteLog("发生错误:" + ex.Message);
                }
            }
    
            /// <summary>
            /// 日志记录
            /// </summary>
            /// <param name="errMsg"></param>
            private static void WriteLog(string errMsg)
            {
                string sFilePath = AppDomain.CurrentDomain.BaseDirectory + "\Log";
                string sFileName = DateTime.Now.ToString("yyyy-MM-dd") + ".log";
                sFileName = sFilePath + "\" + sFileName;
                Directory.CreateDirectory(sFilePath);
                FileStream fs;
                StreamWriter sw;
                if (File.Exists(sFileName))
                    fs = new FileStream(sFileName, FileMode.Append, FileAccess.Write);
                else
                    fs = new FileStream(sFileName, FileMode.Create, FileAccess.Write);
                sw = new StreamWriter(fs);
                sw.WriteLine("时间:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                sw.WriteLine("信息:" + errMsg);
                sw.WriteLine("");
                sw.Close();
                fs.Close();
            }
    
            /// <summary>
            /// 判断端口是否占用
            /// </summary>
            /// <param name="port"></param>
            /// <returns></returns>
            public static bool PortInUse(int port)
            {
                bool inUse = false;
    
                IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
                IPEndPoint[] ipEndPoints = ipProperties.GetActiveTcpListeners();
    
                foreach (IPEndPoint endPoint in ipEndPoints)
                {
                    if (endPoint.Port == port)
                    {
                        inUse = true;
                        break;
                    }
                }
                return inUse;
            }
        }
    }

    其他:程序崩掉,但没有自动关闭控制台的窗体,便不能通过端口监听到是否崩掉,遂修改系统注册表:

    运行注册表编辑器,依次定位到 HKEY_CURRENT_USER\Software\Microsoft\Windows\WindowsError Reporting,
    在右侧窗口中找到并双击打开DontshowUI,然后在弹出的窗口中将默认值“0”修改为“1”。 那么,当程序崩溃时,就不会再出现”xx程序已停止工作”的提示框,崩溃程序进程会自动退出。 这种修改系统注册表的方法是最方便和直接的,但会对所有程序生效。

    如图:

    扩展:如果用配置文件保存信息,按规范只能存一条,如果我们要守护多个程序,就需要保存多条信息,于是将信息保存到xml文件中来处理。

    1. 添加  DataSet.xml 文件

    <?xml version="1.0" encoding="utf-8" ?>
    <Monitor>
      <Second>10</Second>
      <Programs>
        <Program>
          <Port>104</Port>
          <Path>D:项目文件某某系统XXXXXinDebugXXXXXXX.exe</Path>
        </Program>
        <Program>
          <Port>105</Port>
          <Path>D:项目文件某某系统XXXXXinDebug - 副本XXXXXXX.exe</Path>
        </Program>
      </Programs>
    </Monitor>

    2. 重新实现代码

    using System;
    using System.Collections.Generic;
    using System.Configuration;
    using System.Data;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Net.NetworkInformation;
    using System.Text;
    using System.Threading;
    using System.Xml;
    
    namespace Guard
    {
        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    int second = 120; //守护间隔时间
                    DataTable dt = Select("DataSet.xml", out second);
    
                    while (true)
                    {
                        foreach (DataRow row in dt.Rows)
                        {
                            if (!PortInUse(Convert.ToInt32(row["port"]))) //如果监听的端口不存在,就启动对应的程序
                            {
                                Console.WriteLine("启动端口 " + row["port"] + " 的程序");
                                WriteLog("启动端口 " + row["port"] + " 的程序");
                                ProcessHelper.Start(row["path"].ToString());
                            }
                        }
                        Thread.Sleep(second * 1000);
                    }
                }
                catch (Exception ex)
                {
                    WriteLog("发生错误:" + ex);
                    Console.WriteLine(ex);
                }
            }
    
            /// <summary>
            /// 查询xml值
            /// </summary>
            /// <param name="xmlPath"></param>
            /// <param name="second"></param>
            /// <returns></returns>
            public static DataTable Select(string xmlPath, out int second)
            {
                XmlDocument xmlDoc = new XmlDocument();
                try
                {
                    xmlDoc.Load(xmlPath);
                    //var root = xmlDoc.DocumentElement;//取到根结点
                    XmlNode secondChild = xmlDoc.SelectSingleNode("Monitor/Second");    //取指定的单个结点
                    second = Convert.ToInt32(secondChild.InnerText);
                    XmlNode xmldt = xmlDoc.SelectSingleNode("Monitor/Programs");
                    DataSet ds = GetDataSet(xmldt.OuterXml);
                    return ds.Tables["Program"];
                }
                catch (Exception ex)
                {
                    WriteLog("发生错误1:" + ex);
                    Console.WriteLine(ex);
                    second = 120;
                    return null;
                }
            }
    
            /// <summary>
            /// 读取Xml字符串返回DataSet
            /// </summary>
            /// <param name="StringXml">字符串</param>
            /// <returns>DataSet</returns>
            public static DataSet GetDataSet(string StringXml)
            {
                StringReader stringReader = null;
                XmlTextReader xmlTextReader = null;
                DataSet rDataSet = new DataSet();
                try
                {
                    stringReader = new StringReader(StringXml);
                    xmlTextReader = new XmlTextReader(stringReader);
                    rDataSet.ReadXml(xmlTextReader);
                }
                catch (Exception ex)
                {
                    WriteLog("发生错误2:" + ex);
                    Console.WriteLine(ex);
                }
                finally
                {
                    if (xmlTextReader != null)
                    {
    
                        xmlTextReader.Close();
                        stringReader.Close();
                        stringReader.Dispose();
                    }
                }
                return rDataSet;
            }
    
            /// <summary>
            /// 日志记录
            /// </summary>
            /// <param name="errMsg"></param>
            private static void WriteLog(string errMsg)
            {
                string sFilePath = AppDomain.CurrentDomain.BaseDirectory + "\Log";
                string sFileName = DateTime.Now.ToString("yyyy-MM-dd") + ".log";
                sFileName = sFilePath + "\" + sFileName;
                Directory.CreateDirectory(sFilePath);
                FileStream fs;
                StreamWriter sw;
                if (File.Exists(sFileName))
                    fs = new FileStream(sFileName, FileMode.Append, FileAccess.Write);
                else
                    fs = new FileStream(sFileName, FileMode.Create, FileAccess.Write);
                sw = new StreamWriter(fs);
                sw.WriteLine("时间:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                sw.WriteLine("信息:" + errMsg);
                sw.WriteLine("");
                sw.Close();
                fs.Close();
            }
    
            /// <summary>
            /// 判断端口是否占用
            /// </summary>
            /// <param name="port"></param>
            /// <returns></returns>
            public static bool PortInUse(int port)
            {
                bool inUse = false;
    
                IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
                IPEndPoint[] ipEndPoints = ipProperties.GetActiveTcpListeners();
    
                foreach (IPEndPoint endPoint in ipEndPoints)
                {
                    if (endPoint.Port == port)
                    {
                        inUse = true;
                        break;
                    }
                }
                return inUse;
            }
        }
    }
  • 相关阅读:
    Ubuntu:替换DASH图标
    使用 python 操作 mongodb 常用的操作
    boost Asio网络编程简介
    optional的使用
    boost中Function和Lambda的使用
    boost多线程入门介绍
    boost中bind的使用
    c++11新标准for循环和lambda表达式
    使用gcc命令编译多个文件
    编辑gif
  • 原文地址:https://www.cnblogs.com/Allofus/p/15036285.html
Copyright © 2011-2022 走看看