利用WCF的双工通讯实现一个简单的心跳监控系统
发布日期:2021-05-09 09:35:22 浏览次数:11 分类:博客文章

本文共 62455 字,大约阅读时间需要 208 分钟。

何为心跳监控系统?

故名思义,就是监控某个或某些个程序的运行状态,就好比医院里面的心跳监视仪一样,能够随时显示病人的心跳情况。

心跳监控的目的是什么?

与医院里面的心跳监视仪目的类似,监控程序运行状态,一旦出现问题(比如:一些自动运行的服务、程序等突然停止运行了),那么心跳监控系统就能“感知到”并及时的显示在监控界面上,同时可以通过微信、短信告之相关的人员,以便他们及时处理程序异常,从而避免一些自动运行的服务、程序等突然停止运行而造成的一系列损失

心跳监控系统实现的思路是怎样的?

核心技术:WCF的双工通讯

实现步骤:

1.定义WCF的服务契约接口以及回调接口,服务方法主要包括:Start(被监控的程序启动时调用,即通知监控系统,我已经启动了)、Stop(被监控的程序停止时调用,即通知监控系统,我已经停止了)、ReportRunning(被监控的程序运行中定时调用,即通知监控系统,我是正常的并在运行中,同时还起到检测监控系统是否在运行的一个功能,一举两得),回调服务方法应有:Listen(这个是给监控系统主动去定时回调被监控的程序(心跳),如果被监控的程序能正常的返回状态,那么就是正常的,否则有可能已经“死了”,这时监控系统就需要按照预设指令作出相应的操作,比如:监控主界面显示异常的程序,同时发送异常通知消息给相关人员)

2.建立一个心跳监控系统Winform项目,并实现WCF服务,即集成实现WCF服务宿主程序,同时每一个WCF服务方法均需关联界面,即:程序启动了、停止了、运行中均会在界面实时显示出来或做一些实时统计;

3.其它被监控的程序(指自动运行的服务、程序等)需要集成实现WCF回调接口及开启WCF服务通讯的功能;

心跳监控系统的运行顺序是怎样的?如何保证监控方与被监控方实时不间断通讯?

运行顺序:

1.开启心跳监控系统(即:同时开启WCF服务宿主程序),确保监控服务正常运行;

2.开启其它被监控的程序,确保开启客户端与监控系统的WCF双工通讯服务正常;

注意:一定要先开启心跳监控系统,否则其它被监控的程序因无法与监控系统的WCF双工通讯服务正常连接而报错或多次尝试重连;

保证监控方与被监控方实时不间断通讯:

在保证按照上面所说的运行顺序依次开启心跳监控系统,再开启其它被监控的程序,正常建立一次通讯后,后续只要任何一方出现通讯中断,均会自动尝试重连(主要是客户端重连,心跳监控系统除非停止运行,否则不会中断,若因停止运行造成双方通讯中断,只需重启心跳监控系统即可)

通讯模式:

推模式:被监控的程序通过主动的调用WCF服务方法:Start、Stop、ReportRunning 向心跳监控系统告之运行状态,若通讯失败,则自动尝试重连,直至连接成功;

拉模式:心跳监控系统主动回调Listen方法,向被监控的程序索取运行状态,若通讯失败,则会在指定时间内多次重试回调客户端,若客户端在规定的时间范围内仍无法返回消息,则视为客户端异常,那么心跳监控系统则会进行异常的处理;

实现源代码:

ProgramMonitor.Core 类库项目:主要是定义WCF服务的相关接口以及实现回调的接口(因为每个客户端都需实现一遍回调接口,故统一实现,客户端集成后直接可以用,简化集成客户端的开发成本),心跳监控系统及需要被监控的程序均需要依赖该DLL;

ProgramMonitor WINFORM项目:心跳监控系统

整个解决方案如下图示:

注:由于源代码相对较多,故不再一一说明,只对重点的代码作解释

ProgramMonitor.Core

IListenService:(心跳监控WCF服务契约接口)

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.ServiceModel;namespace ProgramMonitor.Core{    [ServiceContract(Namespace = "http://www.zuowenjun.cn", SessionMode = SessionMode.Required, CallbackContract = typeof(IListenCall))]    public interface IListenService    {        [OperationContract(IsOneWay = true)]        void Start(ProgramInfo programInfo);        [OperationContract(IsOneWay = true)]        void Stop(string programId);        [OperationContract(IsOneWay = true)]        void ReportRunning(ProgramInfo programInfo);    }}

IListenCall:(监听回调服务接口,主用被心跳监控系统调用)

using System;using System.Collections.Generic;using System.Linq;using System.ServiceModel;using System.Text;namespace ProgramMonitor.Core{    public interface IListenCall    {        [OperationContract]        int Listen(string programId);    }}

ProgramInfo:(程序信息类,主要用于获取被监控程序的基本信息)

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.ServiceModel;using System.Runtime.Serialization;namespace ProgramMonitor.Core{    [DataContract(Namespace = "http://www.zuowenjun.cn")]    public class ProgramInfo    {        public ProgramInfo()        {        }        [DataMember]        public string Id { get; internal set; }        [DataMember]        public string Name { get; set; }        [DataMember]        public string Version { get; set; }        [DataMember]        public string InstalledLocation { get; set; }        [DataMember]        public string Description { get; set; }        private int runState = -1;        ///         /// 运行状态,-1:表示停止,0表示启动,1表示运行中        ///         [DataMember]        public int RunState        {            get            {                return runState;            }            set            {                this.UpdateStateTime = DateTime.Now;                if (value < 0)                {                    runState = -1;                    this.StopTime = this.UpdateStateTime;                }                else if (value == 0)                {                    runState = 0;                    this.StartTime = this.UpdateStateTime;                }                else                {                    runState = 1;                }            }        }        [DataMember]        public DateTime UpdateStateTime { get; private set; }        [DataMember]        public DateTime StartTime { get; private set; }        [DataMember]        public DateTime StopTime { get; private set; }    }}

 ListenClient:(监听客户端类,实现WCF回调服务接口,主要用于被监控的程序)

using System;using System.Collections.Generic;using System.Diagnostics;using System.IO;using System.Linq;using System.Security.Cryptography;using System.ServiceModel;using System.ServiceModel.Description;using System.Text;namespace ProgramMonitor.Core{    public class ListenClient : IListenCall    {        private static object syncObject = new object();        private static ListenClient instance = null;        private ProgramInfo programInfo = null;        private string serviceHostAddr = null;        private int autoReportRunningInterval = 300;        private DuplexChannelFactory
listenServiceFactory = null; private IListenService proxyListenService = null; private System.Timers.Timer reportRunningTimer = null; private ListenClient(ProgramInfo programInfo, string serviceHostAddr = null, int autoReportRunningInterval = 300) { programInfo.Id = CreateProgramId(); this.programInfo = programInfo; this.serviceHostAddr = serviceHostAddr; if (autoReportRunningInterval >= 60) //最低1分钟的间隔 { this.autoReportRunningInterval = autoReportRunningInterval; } BuildAutoReportRunningTimer(); } private void BuildAutoReportRunningTimer() { reportRunningTimer = new System.Timers.Timer(autoReportRunningInterval * 1000); reportRunningTimer.Elapsed += (s, e) => { ReportRunning(); }; } private void BuildListenClientService() { if (listenServiceFactory == null) { if (string.IsNullOrEmpty(serviceHostAddr)) { serviceHostAddr = System.Configuration.ConfigurationManager.AppSettings["ServiceHostAddr"]; } InstanceContext instanceContext = new InstanceContext(instance); NetTcpBinding binding = new NetTcpBinding(); binding.ReceiveTimeout = new TimeSpan(0, 5, 0); binding.SendTimeout = new TimeSpan(0, 5, 0); Uri baseAddress = new Uri(string.Format("net.tcp://{0}/ListenService", serviceHostAddr)); listenServiceFactory = new DuplexChannelFactory
(instanceContext, binding, new EndpointAddress(baseAddress)); } proxyListenService = listenServiceFactory.CreateChannel(); } public static ListenClient GetInstance(ProgramInfo programInfo, string serviceHostAddr = null, int autoReportRunningInterval = 300) { if (instance == null) { lock (syncObject) { if (instance == null) { instance = new ListenClient(programInfo, serviceHostAddr, autoReportRunningInterval); instance.BuildListenClientService(); } } } return instance; } public void ReportStart() { proxyListenService.Start(programInfo); reportRunningTimer.Start(); } public void ReportStop() { proxyListenService.Stop(programInfo.Id); reportRunningTimer.Stop(); } public void ReportRunning() { try { proxyListenService.ReportRunning(programInfo); } catch { BuildListenClientService(); } } int IListenCall.Listen(string programId) { if (programInfo.Id.Equals(programId, StringComparison.OrdinalIgnoreCase)) { if (programInfo.RunState >= 0) { return 1; } } return -1; } private string CreateProgramId() { Process currProcess = Process.GetCurrentProcess(); int procCount = Process.GetProcessesByName(currProcess.ProcessName).Length; string currentProgramPath = currProcess.MainModule.FileName; return GetMD5HashFromFile(currentProgramPath) + "_" + procCount; } private string GetMD5HashFromFile(string fileName) { try { byte[] hashData = null; using (FileStream fs = new FileStream(fileName, System.IO.FileMode.Open, FileAccess.Read)) { MD5 md5 = new MD5CryptoServiceProvider(); hashData = md5.ComputeHash(fs); fs.Close(); } StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashData.Length; i++) { sb.Append(hashData[i].ToString("x2")); } return sb.ToString(); } catch (Exception ex) { throw new Exception("GetMD5HashFromFile Error:" + ex.Message); } } }}

这里特别说一下:CreateProgramId方法,因为心跳监控系统主要是依据ProgramId来识别每个不同的程序,故ProgramId非常重要,而我这里采用的是文件的 MD5值+进程数作为ProgramId,有些人可能要问,为什么要加进程数呢?原因很简单,因为有些程序是允许开启多个的实例的,如果不加进程数,那么心跳监控系统就无法识别多个同一个程序到底是哪个。

 ProgramMonitor

ListenService:(WCF心跳监控服务接口实现类)

using System;using System.Collections.Generic;using System.Linq;using System.Text;using ProgramMonitor.Core;using System.ServiceModel;namespace ProgramMonitor.Service{    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant, InstanceContextMode = InstanceContextMode.PerCall)]    public class ListenService : IListenService    {        public void Start(ProgramInfo programInfo)        {            var listenCall = OperationContext.Current.GetCallbackChannel
(); Common.SaveProgramStartInfo(programInfo, listenCall); } public void Stop(string programId) { Common.SaveProgramStopInfo(programId); } public void ReportRunning(ProgramInfo programInfo) { var listenCall = OperationContext.Current.GetCallbackChannel
(); Common.SaveProgramRunningInfo(programInfo, listenCall); } }}

Common:(通用业务逻辑类,主要用于WCF与UI实时沟通与联动)

using System;using System.Collections.Generic;using System.Linq;using System.Text;using ProgramMonitor.Core;using System.Collections.Concurrent;using System.Timers;using System.Threading;using Timer = System.Timers.Timer;using ProgramMonitor.Service;using System.Data.SqlClient;using log4net;namespace ProgramMonitor{    public static class Common    {        public static ConcurrentDictionary
ProgramInfos = null; public static ConcurrentDictionary
ListenCalls = null; public static ConcurrentBag
ManualStopProgramIds = null; public static System.Timers.Timer loadTimer = null; public static Timer listenTimer = null; public static SynchronizationContext SyncContext = null; public static Action
RefreshListView; public static Action
RefreshTabControl; public static int ClearInterval = 5; public static int ListenInterval = 2; public static bool Listening = false; public static string DbConnString = null; public static string[] NoticePhoneNos = null; public static string NoticeWxUserIds = null; public static ILog Logger = LogManager.GetLogger("ProgramMonitor"); public const string SqlProviderName = "System.Data.SqlClient"; public static void SaveProgramStartInfo(ProgramInfo programInfo, IListenCall listenCall) { programInfo.RunState = 0; ProgramInfos.AddOrUpdate(programInfo.Id, programInfo, (key, value) => programInfo); ListenCalls.AddOrUpdate(programInfo.Id, listenCall, (key, value) => listenCall); RefreshListView(programInfo, false); RefreshTabControl(programInfo, true); WriteLog(string.Format("程序名:{0},版本:{1},已启动运行", programInfo.Name, programInfo.Version), false); } public static void SaveProgramStopInfo(string programId) { ProgramInfo programInfo; if (ProgramInfos.TryGetValue(programId, out programInfo)) { programInfo.RunState = -1; RefreshListView(programInfo, false); IListenCall listenCall = null; ListenCalls.TryRemove(programId, out listenCall); RefreshTabControl(programInfo, true); } WriteLog(string.Format("程序名:{0},版本:{1},已停止运行", programInfo.Name, programInfo.Version), false); } public static void SaveProgramRunningInfo(ProgramInfo programInfo, IListenCall listenCall) { if (!ProgramInfos.ContainsKey(programInfo.Id) || !ListenCalls.ContainsKey(programInfo.Id)) { SaveProgramStartInfo(programInfo, listenCall); } programInfo.RunState = 1; RefreshTabControl(programInfo, true); WriteLog(string.Format("程序名:{0},版本:{1},正在运行中", programInfo.Name, programInfo.Version), false); } public static void AutoLoadProgramInfos() { if (loadTimer == null) { loadTimer = new Timer(1 * 60 * 1000); loadTimer.Elapsed += delegate(object sender, ElapsedEventArgs e) { var timer = sender as Timer; try { timer.Stop(); foreach (var item in ProgramInfos) { var programInfo = item.Value; RefreshListView(programInfo, false); } } finally { if (Listening) { timer.Start(); } } }; } else { loadTimer.Interval = 1 * 60 * 1000; } loadTimer.Start(); } public static void AutoListenPrograms() { if (listenTimer == null) { listenTimer = new Timer(ListenInterval * 60 * 1000); listenTimer.Elapsed += delegate(object sender, ElapsedEventArgs e) { var timer = sender as Timer; try { timer.Stop(); foreach (var item in ListenCalls) { bool needUpdateStatInfo = false; var listenCall = item.Value; var programInfo = ProgramInfos[item.Key]; int oldRunState = programInfo.RunState; try { programInfo.RunState = listenCall.Listen(programInfo.Id); } catch { if (programInfo.RunState != -1) { programInfo.RunState = -1; needUpdateStatInfo = true; } } if (programInfo.RunState == -1 && programInfo.StopTime.AddMinutes(5) < DateTime.Now) //如果停了5分钟,则发一次短信 { SendNoticeSms(programInfo); SendNoticeWeiXin(programInfo); programInfo.RunState = -1;//重新刷新状态 } if (oldRunState != programInfo.RunState) { needUpdateStatInfo = true; WriteLog(string.Format("程序名:{0},版本:{1},运行状态变更为:{2}", programInfo.Name, programInfo.Version,programInfo.RunState), false); } RefreshTabControl(programInfo, needUpdateStatInfo); } } finally { if (Listening) { timer.Start(); } } }; } else { listenTimer.Interval = ListenInterval * 60 * 1000; } listenTimer.Start(); } public static void SendNoticeSms(ProgramInfo programInfo) { if (NoticePhoneNos == null || NoticePhoneNos.Length <= 0) return; using (DataAccess da = new DataAccess(Common.DbConnString, Common.SqlProviderName)) { da.UseTransaction(); foreach (string phoneNo in NoticePhoneNos) { var parameters = da.ParameterHelper.AddParameter("@Mbno", phoneNo) .AddParameter("@Msg", string.Format("程序名:{0},版本:{1},安装路径:{2},已停止运行了,请尽快处理!", programInfo.Name, programInfo.Version, programInfo.InstalledLocation)) .AddParameter("@SendTime", DateTime.Now) .AddParameter("@KndType", "监控异常通知") .ToParameterArray(); da.ExecuteCommand("insert into OutBox(Mbno,Msg,SendTime,KndType) values(@Mbno,@Msg,@SendTime,@KndType)", paramObjs: parameters); } da.Commit(); WriteLog(string.Format("程序名:{0},版本:{1},已停止运行超过5分钟,成功发送短信通知到:{2}", programInfo.Name, programInfo.Version, string.Join(",", NoticePhoneNos)), false); } } public static void SendNoticeWeiXin(ProgramInfo programInfo) { if (string.IsNullOrEmpty(NoticeWxUserIds)) return; string msg = string.Format("程序名:{0},版本:{1},安装路径:{2},已停止运行了,请尽快处理!", programInfo.Name, programInfo.Version, programInfo.InstalledLocation); var wx = new WeChat(); var result = wx.SendMessage(NoticeWxUserIds, msg); if (result["errmsg"].ToString().Equals("ok", StringComparison.OrdinalIgnoreCase)) { WriteLog(string.Format("程序名:{0},版本:{1},已停止运行超过5分钟,成功发送微信通知到:{2}", programInfo.Name, programInfo.Version,NoticeWxUserIds), false); } } public static void BuildConnectionString(string server, string db, string uid, string pwd) { SqlConnectionStringBuilder connStrBuilder = new SqlConnectionStringBuilder(); connStrBuilder.DataSource = server; connStrBuilder.InitialCatalog = db; connStrBuilder.UserID = uid; connStrBuilder.Password = pwd; connStrBuilder.IntegratedSecurity = false; connStrBuilder.ConnectTimeout = 15; DbConnString = connStrBuilder.ToString(); } public static void WriteLog(string msg, bool isError = false) { if (isError) { Logger.Error(msg); } else { Logger.Info(msg); } } }}

FrmMain:(心跳监控系统窗体类)

using ProgramMonitor.Core;using ProgramMonitor.Service;using System;using System.Collections.Concurrent;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.ServiceModel;using System.ServiceModel.Description;using System.Text;using System.Threading;using System.Windows.Forms;namespace ProgramMonitor{    public partial class FrmMain : Form    {        private ServiceHost serviceHost = null;        public FrmMain()        {            InitializeComponent();            tabControl1.SizeMode = TabSizeMode.Fixed;            tabControl1.ItemSize = new Size(0, 1);#if (DEBUG)            btnTestSend.Visible = true;#else            btnTestSend.Visible = false;#endif            Common.SyncContext = SynchronizationContext.Current;            Common.ProgramInfos = new ConcurrentDictionary
(); Common.ListenCalls = new ConcurrentDictionary
(); Common.ManualStopProgramIds = new ConcurrentBag
(); Common.RefreshListView = RefreshListView; Common.RefreshTabControl = RefreshTabControl; } #region 自定义方法区域 private void RefreshListView(ProgramInfo programInfo, bool needUpdateStatInfo) { Common.SyncContext.Post(o => { string listViewItemKey = string.Format("lvItem_{0}", programInfo.Id); if (!listView1.Items.ContainsKey(listViewItemKey)) { var lstItem = listView1.Items.Add(listViewItemKey, programInfo.Name, 0); lstItem.Name = listViewItemKey; lstItem.Tag = programInfo.Id; lstItem.SubItems.Add(programInfo.Version); lstItem.SubItems.Add(programInfo.InstalledLocation); lstItem.ToolTipText = programInfo.Description; if (needUpdateStatInfo) { UpdateProgramListenStatInfo(); } } else { if (!Common.ListenCalls.ContainsKey(programInfo.Id) && programInfo.RunState == -1 && Common.ClearInterval > 0 && programInfo.StopTime.AddMinutes(Common.ClearInterval) < DateTime.Now) //当属于正常关闭的程序在指定时间后从监控列表中移除 { RemoveListenItem(programInfo.Id); } } }, null); } private void RefreshTabControl(ProgramInfo programInfo, bool needUpdateStatInfo) { Common.SyncContext.Post(o => { string tabPgName = string.Format("tabpg_{0}", programInfo.Id); string msgCtrlName = string.Format("{0}_MsgText", tabPgName); if (!tabControl1.TabPages.ContainsKey(tabPgName)) { RichTextBox rchTextBox = new RichTextBox(); rchTextBox.Name = msgCtrlName; rchTextBox.Dock = DockStyle.Fill; rchTextBox.ReadOnly = true; AppendTextToRichTextBox(rchTextBox, programInfo); var tabPg = new TabPage(); tabPg.Name = tabPgName; tabPg.Controls.Add(rchTextBox); tabControl1.TabPages.Add(tabPg); } else { var tabPg = tabControl1.TabPages[tabPgName]; var rchTextBox = tabPg.Controls[msgCtrlName] as RichTextBox; AppendTextToRichTextBox(rchTextBox, programInfo); } if (needUpdateStatInfo) { UpdateProgramListenStatInfo(); } }, null); } private void UpdateProgramListenStatInfo() { int runCount = Common.ProgramInfos.Count(p => p.Value.RunState >= 0); labRunCount.Text = string.Format("{0}个", runCount); labStopCount.Text = string.Format("{0}个", Common.ProgramInfos.Count - runCount); foreach (ListViewItem lstItem in listView1.Items) { string programId = lstItem.Tag.ToString(); if (Common.ProgramInfos[programId].RunState == -1) { lstItem.ForeColor = Color.Red; } else { lstItem.ForeColor = Color.Black; } } } private void RemoveListenItem(string programInfoId) { ProgramInfo programInfo = Common.ProgramInfos[programInfoId]; listView1.Items.RemoveByKey(string.Format("lvItem_{0}", programInfo.Id)); tabControl1.TabPages.RemoveByKey(string.Format("tabpg_{0}", programInfo.Id)); Common.ProgramInfos.TryRemove(programInfo.Id, out programInfo); IListenCall listenCall = null; Common.ListenCalls.TryRemove(programInfoId, out listenCall); UpdateProgramListenStatInfo(); } private void AppendTextToRichTextBox(RichTextBox rchTextBox, Core.ProgramInfo programInfo) { Color msgColor = Color.Black; string lineMsg = string.Format("{0:yyyy-MM-dd HH:mm}\t{1}({2})\t{3} \n", DateTime.Now, programInfo.Name, programInfo.Version, GetRunStateString(programInfo.RunState, out msgColor)); rchTextBox.SelectionColor = msgColor; rchTextBox.SelectionStart = rchTextBox.Text.Length; rchTextBox.AppendText(lineMsg); rchTextBox.SelectionLength = rchTextBox.Text.Length; if(rchTextBox.Lines.Length>1000) { } } private string GetRunStateString(int runState, out Color msgColor) { if (runState < 0) { msgColor = Color.Red; return "程序已停止运行"; } else if (runState == 0) { msgColor = Color.Blue; return "程序已启动运行"; } else { msgColor = Color.Black; return "程序已在运行中"; } } private void StartListenService() { if (serviceHost == null) { string serviceHostAddr = System.Configuration.ConfigurationManager.AppSettings["ServiceHostAddr"]; string serviceMetaHostAddr = System.Configuration.ConfigurationManager.AppSettings["ServiceMetaHostAddr"]; serviceHost = new ServiceHost(typeof(ListenService)); NetTcpBinding binding = new NetTcpBinding(); binding.ReceiveTimeout = new TimeSpan(0, 5, 0); binding.SendTimeout = new TimeSpan(0, 5, 0); serviceHost.AddServiceEndpoint(typeof(IListenService), binding, string.Format("net.tcp://{0}/ListenService", serviceHostAddr)); if (serviceHost.Description.Behaviors.Find
() == null) { ServiceMetadataBehavior behavior = new ServiceMetadataBehavior(); behavior.HttpGetEnabled = true; behavior.HttpGetUrl = new Uri(string.Format("http://{0}/ListenService/metadata", serviceMetaHostAddr)); serviceHost.Description.Behaviors.Add(behavior); } serviceHost.Opened += (s, arg) => { SetUIStyle("S"); Common.Listening = true; Common.AutoLoadProgramInfos(); Common.AutoListenPrograms(); }; serviceHost.Closed += (s, arg) => { SetUIStyle("C"); Common.loadTimer.Stop(); Common.listenTimer.Stop(); Common.Listening = false; }; } serviceHost.Open(); } private void StopListenService() { try { if (serviceHost != null && serviceHost.State != CommunicationState.Closed) { serviceHost.Close(); } serviceHost = null; } catch { } } private void SetUIStyle(string state) { if (state == "S") { labSericeState.BackColor = Color.Green; txtRefreshInterval.Enabled = false; txtListenInterval.Enabled = false; btnExec.Tag = "C"; btnExec.Text = "停止监控"; panel1.Enabled = false; panel2.Enabled = false; } else { labSericeState.BackColor = Color.Red; txtRefreshInterval.Enabled = true; txtListenInterval.Enabled = true; btnExec.Tag = "S"; btnExec.Text = "开启监控"; panel1.Enabled = true; panel2.Enabled = true; } } private void InitListViewStyle() { ImageList imgList = new ImageList(); imgList.ImageSize = new Size(32, 32); imgList.Images.Add(Properties.Resources.monitor); listView1.SmallImageList = imgList; listView1.LargeImageList = imgList; listView1.View = View.Details; listView1.GridLines = false; listView1.FullRowSelect = true; listView1.Columns.Add("程序名称", -2); listView1.Columns.Add("版本"); listView1.Columns.Add("运行路径"); int avgWidth = listView1.Width / 3; } private void InitNoticeSetting() { if (chkSendSms.Checked) { bool dbConnected = false; Common.BuildConnectionString(txtServer.Text, txtDb.Text, txtUID.Text, txtPwd.Text); using (var da = new DataAccess(Common.DbConnString, Common.SqlProviderName)) { try { da.ExecuteScalar
("select getdate()"); dbConnected = true; } catch (Exception ex) { MessageBox.Show("数据库测试连接失败,原因:" + ex.Message); } } if (dbConnected) { if (txtPhoneNos.Text.Trim().IndexOf(",") >= 0) { Common.NoticePhoneNos = txtPhoneNos.Text.Trim().Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries); } else { Common.NoticePhoneNos = new[] { txtPhoneNos.Text.Trim() }; } } } else { Common.NoticePhoneNos = null; } if (chkSendWx.Checked) { Common.NoticeWxUserIds = txtWxUIDs.Text.Trim(); } else { Common.NoticeWxUserIds = null; } } private bool IsRightClickSelectedItem(Point point) { foreach (ListViewItem item in listView1.SelectedItems) { if (item.Bounds.Contains(point)) { return true; } } return false; } #endregion private void btnExec_Click(object sender, EventArgs e) { string state = (btnExec.Tag ?? "S").ToString(); if (state == "S") { InitNoticeSetting(); Common.ClearInterval = int.Parse(txtRefreshInterval.Text); Common.ListenInterval = int.Parse(txtListenInterval.Text); StartListenService(); } else { StopListenService(); } } private void listView1_SelectedIndexChanged(object sender, EventArgs e) { if (listView1.SelectedItems.Count <= 0) return; string programId = listView1.SelectedItems[0].Tag.ToString(); string tabPgName = string.Format("tabpg_{0}", programId); if (tabControl1.TabPages.ContainsKey(tabPgName)) { tabControl1.SelectedTab = tabControl1.TabPages[tabPgName]; } else { MessageBox.Show("未找到相应的程序监控记录!"); listView1.SelectedItems[0].ForeColor = Color.Red; } } private void FrmMain_Load(object sender, EventArgs e) { InitListViewStyle(); } private void FrmMain_FormClosing(object sender, FormClosingEventArgs e) { if (MessageBox.Show("您确定要退出吗?退出后将无法正常监控各程序的运行状况", "退出提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.Cancel) { e.Cancel = true; return; } StopListenService(); } private void btnTestSend_Click(object sender, EventArgs e) { var wx = new WeChat(); var msg = wx.SendMessage("kyezuo", "测试消息,有程序停止运行了,赶紧处理!"); MessageBox.Show(msg["errmsg"].ToString()); } private void listView1_MouseUp(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Right && IsRightClickSelectedItem(e.Location)) { ctxMuPop.Show(listView1, e.Location); } } private void removeToolStripMenuItem_Click(object sender, EventArgs e) { if (listView1.SelectedItems.Count <= 0) return; string programId = listView1.SelectedItems[0].Tag.ToString(); if (Common.ProgramInfos[programId].RunState != -1) { MessageBox.Show("只有被监控的程序处于已停止状态的监控项才能移除,除外情况请务必保持正常!"); return; } RemoveListenItem(programId); } }}

窗体类中主要是用到了几个更新UI上控件信息的方法以及开启、关闭WCF服务的方法,很简单,一看就明白,无需多讲。

FrmMain.Designer.cs:(Form窗体设计类,系统自动生成的,再此贴出是便于大家可以直接COPY到自己的代码中直接用)

namespace ProgramMonitor{    partial class FrmMain    {        ///         /// 必需的设计器变量。        ///         private System.ComponentModel.IContainer components = null;        ///         /// 清理所有正在使用的资源。        ///         /// 如果应释放托管资源,为 true;否则为 false。        protected override void Dispose(bool disposing)        {            if (disposing && (components != null))            {                components.Dispose();            }            base.Dispose(disposing);        }        #region Windows 窗体设计器生成的代码        ///         /// 设计器支持所需的方法 - 不要        /// 使用代码编辑器修改此方法的内容。        ///         private void InitializeComponent()        {            this.components = new System.ComponentModel.Container();            this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();            this.splitContainer1 = new System.Windows.Forms.SplitContainer();            this.listView1 = new System.Windows.Forms.ListView();            this.tabControl1 = new System.Windows.Forms.TabControl();            this.tabControl2 = new System.Windows.Forms.TabControl();            this.tabPage1 = new System.Windows.Forms.TabPage();            this.groupBox1 = new System.Windows.Forms.GroupBox();            this.btnTestSend = new System.Windows.Forms.Button();            this.labSericeState = new System.Windows.Forms.Label();            this.btnExec = new System.Windows.Forms.Button();            this.txtListenInterval = new System.Windows.Forms.TextBox();            this.txtRefreshInterval = new System.Windows.Forms.TextBox();            this.labStopCount = new System.Windows.Forms.Label();            this.labRunCount = new System.Windows.Forms.Label();            this.label4 = new System.Windows.Forms.Label();            this.label3 = new System.Windows.Forms.Label();            this.label2 = new System.Windows.Forms.Label();            this.label1 = new System.Windows.Forms.Label();            this.tabPage2 = new System.Windows.Forms.TabPage();            this.labLine = new System.Windows.Forms.Label();            this.panel1 = new System.Windows.Forms.Panel();            this.txtPwd = new System.Windows.Forms.TextBox();            this.txtUID = new System.Windows.Forms.TextBox();            this.txtDb = new System.Windows.Forms.TextBox();            this.txtServer = new System.Windows.Forms.TextBox();            this.label8 = new System.Windows.Forms.Label();            this.label9 = new System.Windows.Forms.Label();            this.txtPhoneNos = new System.Windows.Forms.TextBox();            this.label7 = new System.Windows.Forms.Label();            this.label6 = new System.Windows.Forms.Label();            this.label5 = new System.Windows.Forms.Label();            this.chkSendSms = new System.Windows.Forms.CheckBox();            this.panel2 = new System.Windows.Forms.Panel();            this.txtWxUIDs = new System.Windows.Forms.TextBox();            this.chkSendWx = new System.Windows.Forms.CheckBox();            this.label10 = new System.Windows.Forms.Label();            this.ctxMuPop = new System.Windows.Forms.ContextMenuStrip(this.components);            this.removeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();            this.tableLayoutPanel1.SuspendLayout();            ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();            this.splitContainer1.Panel1.SuspendLayout();            this.splitContainer1.Panel2.SuspendLayout();            this.splitContainer1.SuspendLayout();            this.tabControl2.SuspendLayout();            this.tabPage1.SuspendLayout();            this.groupBox1.SuspendLayout();            this.tabPage2.SuspendLayout();            this.panel1.SuspendLayout();            this.panel2.SuspendLayout();            this.ctxMuPop.SuspendLayout();            this.SuspendLayout();            //             // tableLayoutPanel1            //             this.tableLayoutPanel1.ColumnCount = 1;            this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));            this.tableLayoutPanel1.Controls.Add(this.splitContainer1, 0, 1);            this.tableLayoutPanel1.Controls.Add(this.tabControl2, 0, 0);            this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;            this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);            this.tableLayoutPanel1.Name = "tableLayoutPanel1";            this.tableLayoutPanel1.RowCount = 2;            this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 150F));            this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());            this.tableLayoutPanel1.Size = new System.Drawing.Size(1039, 722);            this.tableLayoutPanel1.TabIndex = 0;            //             // splitContainer1            //             this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;            this.splitContainer1.FixedPanel = System.Windows.Forms.FixedPanel.Panel1;            this.splitContainer1.Location = new System.Drawing.Point(3, 153);            this.splitContainer1.Name = "splitContainer1";            //             // splitContainer1.Panel1            //             this.splitContainer1.Panel1.AutoScroll = true;            this.splitContainer1.Panel1.Controls.Add(this.listView1);            this.splitContainer1.Panel1MinSize = 150;            //             // splitContainer1.Panel2            //             this.splitContainer1.Panel2.Controls.Add(this.tabControl1);            this.splitContainer1.Panel2MinSize = 500;            this.splitContainer1.Size = new System.Drawing.Size(1033, 608);            this.splitContainer1.SplitterDistance = 296;            this.splitContainer1.TabIndex = 0;            //             // listView1            //             this.listView1.Dock = System.Windows.Forms.DockStyle.Fill;            this.listView1.Location = new System.Drawing.Point(0, 0);            this.listView1.Name = "listView1";            this.listView1.Size = new System.Drawing.Size(296, 608);            this.listView1.TabIndex = 0;            this.listView1.UseCompatibleStateImageBehavior = false;            this.listView1.View = System.Windows.Forms.View.Details;            this.listView1.SelectedIndexChanged += new System.EventHandler(this.listView1_SelectedIndexChanged);            this.listView1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.listView1_MouseUp);            //             // tabControl1            //             this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill;            this.tabControl1.Location = new System.Drawing.Point(0, 0);            this.tabControl1.Margin = new System.Windows.Forms.Padding(3, 0, 3, 3);            this.tabControl1.Name = "tabControl1";            this.tabControl1.SelectedIndex = 0;            this.tabControl1.Size = new System.Drawing.Size(733, 608);            this.tabControl1.TabIndex = 0;            //             // tabControl2            //             this.tabControl2.Controls.Add(this.tabPage1);            this.tabControl2.Controls.Add(this.tabPage2);            this.tabControl2.Dock = System.Windows.Forms.DockStyle.Fill;            this.tabControl2.Location = new System.Drawing.Point(3, 3);            this.tabControl2.Name = "tabControl2";            this.tabControl2.SelectedIndex = 0;            this.tabControl2.Size = new System.Drawing.Size(1033, 144);            this.tabControl2.TabIndex = 1;            //             // tabPage1            //             this.tabPage1.Controls.Add(this.groupBox1);            this.tabPage1.Location = new System.Drawing.Point(4, 22);            this.tabPage1.Name = "tabPage1";            this.tabPage1.Padding = new System.Windows.Forms.Padding(3);            this.tabPage1.Size = new System.Drawing.Size(1025, 118);            this.tabPage1.TabIndex = 0;            this.tabPage1.Text = "监控基本信息";            this.tabPage1.UseVisualStyleBackColor = true;            //             // groupBox1            //             this.groupBox1.Controls.Add(this.btnTestSend);            this.groupBox1.Controls.Add(this.labSericeState);            this.groupBox1.Controls.Add(this.btnExec);            this.groupBox1.Controls.Add(this.txtListenInterval);            this.groupBox1.Controls.Add(this.txtRefreshInterval);            this.groupBox1.Controls.Add(this.labStopCount);            this.groupBox1.Controls.Add(this.labRunCount);            this.groupBox1.Controls.Add(this.label4);            this.groupBox1.Controls.Add(this.label3);            this.groupBox1.Controls.Add(this.label2);            this.groupBox1.Controls.Add(this.label1);            this.groupBox1.Dock = System.Windows.Forms.DockStyle.Fill;            this.groupBox1.Location = new System.Drawing.Point(3, 3);            this.groupBox1.Name = "groupBox1";            this.groupBox1.Size = new System.Drawing.Size(1019, 112);            this.groupBox1.TabIndex = 1;            this.groupBox1.TabStop = false;            //             // btnTestSend            //             this.btnTestSend.Location = new System.Drawing.Point(14, 73);            this.btnTestSend.Name = "btnTestSend";            this.btnTestSend.Size = new System.Drawing.Size(123, 23);            this.btnTestSend.TabIndex = 4;            this.btnTestSend.Text = "测试发送消息";            this.btnTestSend.UseVisualStyleBackColor = true;            this.btnTestSend.Click += new System.EventHandler(this.btnTestSend_Click);            //             // labSericeState            //             this.labSericeState.BackColor = System.Drawing.Color.Red;            this.labSericeState.Location = new System.Drawing.Point(578, 40);            this.labSericeState.Name = "labSericeState";            this.labSericeState.Size = new System.Drawing.Size(34, 22);            this.labSericeState.TabIndex = 3;            this.labSericeState.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;            //             // btnExec            //             this.btnExec.Location = new System.Drawing.Point(487, 40);            this.btnExec.Name = "btnExec";            this.btnExec.Size = new System.Drawing.Size(75, 23);            this.btnExec.TabIndex = 2;            this.btnExec.Text = "开启监控";            this.btnExec.UseVisualStyleBackColor = true;            this.btnExec.Click += new System.EventHandler(this.btnExec_Click);            //             // txtListenInterval            //             this.txtListenInterval.Location = new System.Drawing.Point(147, 41);            this.txtListenInterval.Name = "txtListenInterval";            this.txtListenInterval.Size = new System.Drawing.Size(68, 21);            this.txtListenInterval.TabIndex = 1;            this.txtListenInterval.Text = "2";            //             // txtRefreshInterval            //             this.txtRefreshInterval.Location = new System.Drawing.Point(411, 41);            this.txtRefreshInterval.Name = "txtRefreshInterval";            this.txtRefreshInterval.Size = new System.Drawing.Size(68, 21);            this.txtRefreshInterval.TabIndex = 1;            this.txtRefreshInterval.Text = "5";            //             // labStopCount            //             this.labStopCount.AutoSize = true;            this.labStopCount.Font = new System.Drawing.Font("宋体", 14.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));            this.labStopCount.ForeColor = System.Drawing.Color.Red;            this.labStopCount.Location = new System.Drawing.Point(841, 42);            this.labStopCount.Name = "labStopCount";            this.labStopCount.Size = new System.Drawing.Size(40, 19);            this.labStopCount.TabIndex = 0;            this.labStopCount.Text = "0个";            //             // labRunCount            //             this.labRunCount.AutoSize = true;            this.labRunCount.Font = new System.Drawing.Font("宋体", 14.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));            this.labRunCount.ForeColor = System.Drawing.Color.Green;            this.labRunCount.Location = new System.Drawing.Point(721, 42);            this.labRunCount.Name = "labRunCount";            this.labRunCount.Size = new System.Drawing.Size(40, 19);            this.labRunCount.TabIndex = 0;            this.labRunCount.Text = "0个";            //             // label4            //             this.label4.AutoSize = true;            this.label4.Location = new System.Drawing.Point(782, 45);            this.label4.Name = "label4";            this.label4.Size = new System.Drawing.Size(53, 12);            this.label4.TabIndex = 0;            this.label4.Text = "已停止:";            //             // label3            //             this.label3.AutoSize = true;            this.label3.Location = new System.Drawing.Point(645, 45);            this.label3.Name = "label3";            this.label3.Size = new System.Drawing.Size(53, 12);            this.label3.TabIndex = 0;            this.label3.Text = "运行中:";            //             // label2            //             this.label2.AutoSize = true;            this.label2.Location = new System.Drawing.Point(12, 45);            this.label2.Name = "label2";            this.label2.Size = new System.Drawing.Size(125, 12);            this.label2.TabIndex = 0;            this.label2.Text = "监听探测间隔(分):";            //             // label1            //             this.label1.AutoSize = true;            this.label1.Location = new System.Drawing.Point(232, 45);            this.label1.Name = "label1";            this.label1.Size = new System.Drawing.Size(173, 12);            this.label1.TabIndex = 0;            this.label1.Text = "正常停止清除列表时长(分):";            //             // tabPage2            //             this.tabPage2.Controls.Add(this.labLine);            this.tabPage2.Controls.Add(this.panel1);            this.tabPage2.Controls.Add(this.panel2);            this.tabPage2.Location = new System.Drawing.Point(4, 22);            this.tabPage2.Name = "tabPage2";            this.tabPage2.Padding = new System.Windows.Forms.Padding(3);            this.tabPage2.Size = new System.Drawing.Size(1025, 118);            this.tabPage2.TabIndex = 1;            this.tabPage2.Text = "消息通知设置";            this.tabPage2.UseVisualStyleBackColor = true;            //             // labLine            //             this.labLine.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));            this.labLine.Dock = System.Windows.Forms.DockStyle.Bottom;            this.labLine.FlatStyle = System.Windows.Forms.FlatStyle.Popup;            this.labLine.Location = new System.Drawing.Point(3, 59);            this.labLine.Name = "labLine";            this.labLine.Size = new System.Drawing.Size(1019, 2);            this.labLine.TabIndex = 0;            //             // panel1            //             this.panel1.Controls.Add(this.txtPwd);            this.panel1.Controls.Add(this.txtUID);            this.panel1.Controls.Add(this.txtDb);            this.panel1.Controls.Add(this.txtServer);            this.panel1.Controls.Add(this.label8);            this.panel1.Controls.Add(this.label9);            this.panel1.Controls.Add(this.txtPhoneNos);            this.panel1.Controls.Add(this.label7);            this.panel1.Controls.Add(this.label6);            this.panel1.Controls.Add(this.label5);            this.panel1.Controls.Add(this.chkSendSms);            this.panel1.Dock = System.Windows.Forms.DockStyle.Top;            this.panel1.Location = new System.Drawing.Point(3, 3);            this.panel1.Name = "panel1";            this.panel1.Size = new System.Drawing.Size(1019, 52);            this.panel1.TabIndex = 0;            //             // txtPwd            //             this.txtPwd.Location = new System.Drawing.Point(925, 24);            this.txtPwd.Name = "txtPwd";            this.txtPwd.PasswordChar = '*';            this.txtPwd.Size = new System.Drawing.Size(91, 21);            this.txtPwd.TabIndex = 5;            //             // txtUID            //             this.txtUID.Location = new System.Drawing.Point(779, 24);            this.txtUID.Name = "txtUID";            this.txtUID.PasswordChar = '*';            this.txtUID.Size = new System.Drawing.Size(91, 21);            this.txtUID.TabIndex = 4;            //             // txtDb            //             this.txtDb.Location = new System.Drawing.Point(628, 24);            this.txtDb.Name = "txtDb";            this.txtDb.Size = new System.Drawing.Size(96, 21);            this.txtDb.TabIndex = 3;            this.txtDb.Text = "";            //             // txtServer            //             this.txtServer.Location = new System.Drawing.Point(423, 24);            this.txtServer.Name = "txtServer";            this.txtServer.Size = new System.Drawing.Size(150, 21);            this.txtServer.TabIndex = 2;            this.txtServer.Text = "";            //             // label8            //             this.label8.AutoSize = true;            this.label8.Location = new System.Drawing.Point(876, 27);            this.label8.Name = "label8";            this.label8.Size = new System.Drawing.Size(41, 12);            this.label8.TabIndex = 7;            this.label8.Text = "密码:";            //             // label9            //             this.label9.AutoSize = true;            this.label9.Location = new System.Drawing.Point(579, 27);            this.label9.Name = "label9";            this.label9.Size = new System.Drawing.Size(53, 12);            this.label9.TabIndex = 7;            this.label9.Text = "数据库:";            //             // txtPhoneNos            //             this.txtPhoneNos.Location = new System.Drawing.Point(213, 22);            this.txtPhoneNos.Name = "txtPhoneNos";            this.txtPhoneNos.Size = new System.Drawing.Size(155, 21);            this.txtPhoneNos.TabIndex = 1;            //             // label7            //             this.label7.AutoSize = true;            this.label7.Location = new System.Drawing.Point(730, 27);            this.label7.Name = "label7";            this.label7.Size = new System.Drawing.Size(53, 12);            this.label7.TabIndex = 7;            this.label7.Text = "用户名:";            //             // label6            //             this.label6.AutoSize = true;            this.label6.Location = new System.Drawing.Point(374, 27);            this.label6.Name = "label6";            this.label6.Size = new System.Drawing.Size(53, 12);            this.label6.TabIndex = 7;            this.label6.Text = "服务器:";            //             // label5            //             this.label5.AutoSize = true;            this.label5.Location = new System.Drawing.Point(3, 27);            this.label5.Name = "label5";            this.label5.Size = new System.Drawing.Size(185, 12);            this.label5.TabIndex = 7;            this.label5.Text = "通知手机号(多个请用,分隔):";            //             // chkSendSms            //             this.chkSendSms.AutoSize = true;            this.chkSendSms.Location = new System.Drawing.Point(3, 3);            this.chkSendSms.Name = "chkSendSms";            this.chkSendSms.Size = new System.Drawing.Size(72, 16);            this.chkSendSms.TabIndex = 0;            this.chkSendSms.Text = "短信通知";            this.chkSendSms.UseVisualStyleBackColor = true;            //             // panel2            //             this.panel2.Controls.Add(this.txtWxUIDs);            this.panel2.Controls.Add(this.chkSendWx);            this.panel2.Controls.Add(this.label10);            this.panel2.Dock = System.Windows.Forms.DockStyle.Bottom;            this.panel2.Location = new System.Drawing.Point(3, 61);            this.panel2.Name = "panel2";            this.panel2.Size = new System.Drawing.Size(1019, 54);            this.panel2.TabIndex = 1;            //             // txtWxUIDs            //             this.txtWxUIDs.Location = new System.Drawing.Point(188, 15);            this.txtWxUIDs.Name = "txtWxUIDs";            this.txtWxUIDs.Size = new System.Drawing.Size(828, 21);            this.txtWxUIDs.TabIndex = 0;            this.txtWxUIDs.Text = "@all";            //             // chkSendWx            //             this.chkSendWx.AutoSize = true;            this.chkSendWx.Location = new System.Drawing.Point(3, 3);            this.chkSendWx.Name = "chkSendWx";            this.chkSendWx.Size = new System.Drawing.Size(72, 16);            this.chkSendWx.TabIndex = 6;            this.chkSendWx.Text = "微信通知";            this.chkSendWx.UseVisualStyleBackColor = true;            //             // label10            //             this.label10.AutoSize = true;            this.label10.Location = new System.Drawing.Point(3, 24);            this.label10.Name = "label10";            this.label10.Size = new System.Drawing.Size(179, 12);            this.label10.TabIndex = 7;            this.label10.Text = "通知微信ID(多个请用|分隔):";            //             // ctxMuPop            //             this.ctxMuPop.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {            this.removeToolStripMenuItem});            this.ctxMuPop.Name = "ctxMuPop";            this.ctxMuPop.Size = new System.Drawing.Size(125, 26);            //             // removeToolStripMenuItem            //             this.removeToolStripMenuItem.Name = "removeToolStripMenuItem";            this.removeToolStripMenuItem.Size = new System.Drawing.Size(124, 22);            this.removeToolStripMenuItem.Text = "移除监控";            this.removeToolStripMenuItem.Click += new System.EventHandler(this.removeToolStripMenuItem_Click);            //             // FrmMain            //             this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;            this.ClientSize = new System.Drawing.Size(1039, 722);            this.Controls.Add(this.tableLayoutPanel1);            this.Name = "FrmMain";            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;            this.Text = "程序运行状态监控系统";            this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FrmMain_FormClosing);            this.Load += new System.EventHandler(this.FrmMain_Load);            this.tableLayoutPanel1.ResumeLayout(false);            this.splitContainer1.Panel1.ResumeLayout(false);            this.splitContainer1.Panel2.ResumeLayout(false);            ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit();            this.splitContainer1.ResumeLayout(false);            this.tabControl2.ResumeLayout(false);            this.tabPage1.ResumeLayout(false);            this.groupBox1.ResumeLayout(false);            this.groupBox1.PerformLayout();            this.tabPage2.ResumeLayout(false);            this.panel1.ResumeLayout(false);            this.panel1.PerformLayout();            this.panel2.ResumeLayout(false);            this.panel2.PerformLayout();            this.ctxMuPop.ResumeLayout(false);            this.ResumeLayout(false);        }        #endregion        private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;        private System.Windows.Forms.SplitContainer splitContainer1;        private System.Windows.Forms.ListView listView1;        private System.Windows.Forms.GroupBox groupBox1;        private System.Windows.Forms.TextBox txtListenInterval;        private System.Windows.Forms.Label label2;        private System.Windows.Forms.Label labStopCount;        private System.Windows.Forms.Label labRunCount;        private System.Windows.Forms.Label label4;        private System.Windows.Forms.Label label3;        private System.Windows.Forms.Button btnExec;        private System.Windows.Forms.TabControl tabControl1;        private System.Windows.Forms.Label labSericeState;        private System.Windows.Forms.TextBox txtRefreshInterval;        private System.Windows.Forms.Label label1;        private System.Windows.Forms.TabControl tabControl2;        private System.Windows.Forms.TabPage tabPage1;        private System.Windows.Forms.TabPage tabPage2;        private System.Windows.Forms.Panel panel2;        private System.Windows.Forms.CheckBox chkSendWx;        private System.Windows.Forms.Label label10;        private System.Windows.Forms.TextBox txtWxUIDs;        private System.Windows.Forms.Panel panel1;        private System.Windows.Forms.TextBox txtPwd;        private System.Windows.Forms.TextBox txtUID;        private System.Windows.Forms.TextBox txtDb;        private System.Windows.Forms.TextBox txtServer;        private System.Windows.Forms.Label label8;        private System.Windows.Forms.Label label9;        private System.Windows.Forms.TextBox txtPhoneNos;        private System.Windows.Forms.Label label7;        private System.Windows.Forms.Label label6;        private System.Windows.Forms.Label label5;        private System.Windows.Forms.CheckBox chkSendSms;        private System.Windows.Forms.Label labLine;        private System.Windows.Forms.Button btnTestSend;        private System.Windows.Forms.ContextMenuStrip ctxMuPop;        private System.Windows.Forms.ToolStripMenuItem removeToolStripMenuItem;    }}

被监控的客户端程序集成WCF监听客户端很简单,只需引用ProgramMonitor.Core,然后实例化ListenClient,最后就可以通过该ListenClient与心跳监控系统进行双工通讯,在此就不贴出源代码了。

上述代码中还有用到两个类:

DataAccess:数据访问类,这个我之前的文章有介绍,详见:

WeChat:微信企业号发送消息类,注意是微信企业号,不是公众号,这里我也贴出源代码来,供大家了解:

using Newtonsoft.Json;using Newtonsoft.Json.Linq;using System;using System.Collections.Generic;using System.IO;using System.Linq;using System.Net;using System.Text;using System.Web;namespace ProgramMonitor.Service{    public class WeChat    {        private readonly string _url = null;        private readonly string _corpid = null;        private readonly string _secret = null;        public WeChat()        {            _url = "https://qyapi.weixin.qq.com/cgi-bin";            _corpid = "CorpID是企业号的标识,每个企业号拥有一个唯一的CorpID";            _secret = "secret是管理组凭证密钥,系统管理员在企业号管理后台创建管理组时,企业号后台为该管理组分配一个唯一的secret";        }        public string GetToken(string url_prefix = "/")        {            string urlParams = string.Format("corpid={0}&corpsecret={1}", HttpUtility.UrlEncodeUnicode(_corpid), HttpUtility.UrlEncodeUnicode(_secret));            string url = _url + url_prefix + "gettoken?" + urlParams;            string result = HttpGet(url);            var content = JObject.Parse(result);            return content["access_token"].ToString();        }        public JObject PostData(dynamic data, string url_prefix = "/")        {            string dataStr = JsonConvert.SerializeObject(data);            string url = _url + url_prefix + "message/send?access_token=" + GetToken();            string result = HttpPost(url, dataStr);            return JObject.Parse(result);        }        public JObject SendMessage(string touser, string message)        {            var data = new { touser = touser, toparty = "1", msgtype = "text", agentid = "2", text = new { content = message }, safe = "0" };            var jResult = PostData(data);            return jResult;        }        private string HttpPost(string Url, string postDataStr)        {            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url);            request.Method = "POST";            request.ContentType = "application/x-www-form-urlencoded";            byte[] data = Encoding.UTF8.GetBytes(postDataStr);            request.ContentLength = data.Length;            Stream myRequestStream = request.GetRequestStream();            myRequestStream.Write(data, 0, data.Length);            myRequestStream.Close();            HttpWebResponse response = (HttpWebResponse)request.GetResponse();            Stream myResponseStream = response.GetResponseStream();            StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.UTF8);            string retString = myStreamReader.ReadToEnd();            myStreamReader.Close();            myResponseStream.Close();            return retString;        }        public string HttpGet(string Url, string urlParams = null)        {            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url + (string.IsNullOrEmpty(urlParams) ? "" : "?") + urlParams);            request.Method = "GET";            request.ContentType = "text/html;charset=UTF-8";            HttpWebResponse response = (HttpWebResponse)request.GetResponse();            Stream myResponseStream = response.GetResponseStream();            StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.UTF8);            string retString = myStreamReader.ReadToEnd();            myStreamReader.Close();            myResponseStream.Close();            return retString;        }    }}

具体的关于微信企业号开发文档,可参见:http://qydev.weixin.qq.com/wiki/index.php

最后的效果如下:

心跳监控程序监控效果:

手机收到异常消息:

  (《-这是企业号发出的消息)                    (《-这里短信消息,当然发短信是我公司的平台接口发出的,发短信是需要RMB的,故不建议)

 

好了本文就到此结束,可能功能相对简单,还有一些不足,欢迎大家评论交流,谢谢!

 

上一篇:c#+handle.exe实现升级程序在运行时自动解除文件被占用的问题
下一篇:通过三个DEMO学会SignalR的三种实现方式

发表评论

最新留言

感谢大佬
[***.8.128.20]2025年04月10日 04时22分16秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章