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;
            }
        }
    }
  • 相关阅读:
    windows的80端口被占用时的处理方法
    Ansible自动化运维工具安装与使用实例
    Tomcat的测试网页换成自己项目首页
    LeetCode 219. Contains Duplicate II
    LeetCode Contest 177
    LeetCode 217. Contains Duplicate
    LeetCode 216. Combination Sum III(DFS)
    LeetCode 215. Kth Largest Element in an Array(排序)
    Contest 176 LeetCode 1354. Construct Target Array With Multiple Sums(优先队列,递推)
    Contest 176
  • 原文地址:https://www.cnblogs.com/Allofus/p/15036285.html
Copyright © 2011-2022 走看看