使用命名管道NamePipe实现服务看门狗功能并附C#源码
使用命名管道NamePipe实现服务看门狗功能
程序或服务中经常会碰到很多异常情况,需要实现杀掉自身进程然后重新启动的情况, 即类似于硬件上看门狗的功能。
关于命名管道(NamePipe)可以参考如何:使用命名管道进行网络进程间通信。
这里是通过在服务子进程中通过NamePipeServer每隔固定时间(此处设置为15秒)发送一次心跳包myheartbeat, 然后在主进程中实现NamePipeClient中接收这个心跳包,更新最后一次心跳包的时间,如果超过固定的最大间隔时间(此处为2*60秒)则通过Application.Restart()重启服务。
管道名称PipeName必须设置相同, 此处为“FaceOfflineRestNamePipe”
1.NamePipeServer
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.IO.Pipes;
using NLog;
namespace HTTPServerLib
{
/// <summary>
/// NamePipeServer
/// </summary>
public class NamePipeServer
{
/// <summary>
/// Logger for xxxx
/// </summary>
public static Logger logger = LogManager.GetLogger("FaceOfflineRest");
private NamedPipeServerStream _pipe;
private const string PipeName = "FaceOfflineRestNamePipe";
private const int PipeInBufferSize = 4096;
private const int PipeOutBufferSize = 65535;
private Encoding encoding = Encoding.UTF8;
/// <summary>
/// StartNamePipe
/// </summary>
public void StartNamePipe()
{
_pipe = new NamedPipeServerStream
(
PipeName,
PipeDirection.InOut,
1,
PipeTransmissionMode.Message,
PipeOptions.Asynchronous | PipeOptions.WriteThrough,
PipeInBufferSize,
PipeOutBufferSize
);
//logger.Info("NamePipeServer.Waiting for client connection...");
_pipe.WaitForConnection();
//logger.Info("NamePipeServer.Client connected.");
}
/// <summary>
/// SendMessage
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public void SendMessage(string message)
{
if (!_pipe.IsConnected)
{
logger.Error("NamePipeServer.SendMessage: pipe not connected,try to restart...");
_pipe.Close();
StartNamePipe();
}
//
try
{
using (StreamWriter sw = new StreamWriter(_pipe))
{
sw.AutoFlush = true;
sw.Write(message);
}
}
catch (Exception ex)
{
logger.Error("NamePipeServer.SendMessage: ex: " + ex.Message);
}
}
}
}
2.进程引用
private void ProcessRequestInQue()
{
DateTime start = DateTime.Now;
TimeSpan ts = DateTime.Now - start;
while (IsRunning)
{
if(reqClientQue.Count >0)
{
logger.Info("\nCurrent task number:{0}", reqClientQue.Count.ToString());
TcpClient client = (TcpClient)reqClientQue.Dequeue();
ProcessRequest(client);
}
ts = DateTime.Now - start;
if(ts.TotalSeconds >= 15)
{
start = DateTime.Now;
LocalMachineAction("myheartbeat");
}
Thread.Sleep(5);
}
}
private static void LocalMachineAction(string command)
{
NamePipeServer nps = new NamePipeServer();
nps.StartNamePipe();
nps.SendMessage(command);
}
3.NameClient,此处代码没有实际应用供参考,具体实现代码参见下方命名管道进程
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NLog;
using System.IO;
using System.IO.Pipes;
namespace FaceOfflineRest
{
public class NamePipeClient
{
/// <summary>
/// Logger for xxxx
/// </summary>
public static Logger logger = LogManager.GetLogger("FaceOfflineRest");
private const string PipeName = "FaceOfflineRestNamePipe";
private Encoding encoding = Encoding.UTF8;
private NamedPipeClientStream _pipe;
public bool _starting = false;
public void connect()
{
if (_starting)
{
return;
}
try
{
_pipe = new NamedPipeClientStream
(
".",
PipeName,
PipeDirection.InOut,
PipeOptions.Asynchronous | PipeOptions.WriteThrough
);
_pipe.Connect();
_pipe.ReadMode = PipeTransmissionMode.Message;
string message = "NamePipe Connected!";
byte[] data = encoding.GetBytes(message);
_pipe.BeginWrite(data, 0, data.Length, PipeWriteCallback, _pipe);
_starting = true;
}
catch (Exception ex)
{
logger.Error("NamePipeClient.connect, Exception:" + ex.Message + ex.StackTrace);
_starting = false;
}
}
private void PipeWriteCallback(IAsyncResult ar)
{
try
{
var pipe = (NamedPipeClientStream)ar.AsyncState;
pipe.EndWrite(ar);
pipe.Flush();
pipe.WaitForPipeDrain();
var data = new byte[65535];
var count = pipe.Read(data, 0, data.Length);
if (count > 0)
{
string message = encoding.GetString(data, 0, count);
logger.Info("NamePipe Received: " + message);
}
}
catch (Exception ex)
{
logger.Error("NamePipeClient.PipeWriteCallback, Exception:" + ex.Message + ex.StackTrace);
_starting = false;
}
}
}
}
4.命名管道及重启服务线程
//NamePipe
private static bool _namepiperunflag = true;
private static int _namepipe_in_milisecond = 100; //100ms
private const string PipeName = "FaceOfflineRestNamePipe";
private Encoding encoding = Encoding.UTF8;
private static NamedPipeClientStream _pipe;
#region 新开线程用于创建NamePipeServer,接收NamePipeClient发来的消息进行处理
/// <summary>
/// 命名管道t_namepipe
/// </summary>
private static Thread t_namepipe = null;
private static Thread t_restart = null;
private static DateTime last_heartbeat_time = DateTime.Now;
private static object syncstate = new object();
/// <summary>
/// 命名管道线程
/// </summary>
private static void ThreadNamePipeWork()
{
t_namepipe = new Thread(new ThreadStart(ThreadNamePipe));
t_namepipe.Start();
logger.Info("FaceOfflineRest.ThreadNamePipeWork.ThreadNamePipe启动!");
t_restart = new Thread(new ThreadStart(ThreadRestart));
t_restart.Start();
logger.Info("FaceOfflineRest.ThreadNamePipeWork.ThreadRestart启动!");
}
private static void ThreadRestart()
{
try
{
TimeSpan ts = DateTime.Now - DateTime.Now.AddSeconds(-360);
while (_namepiperunflag)
{
//logger.Info("ThreadNamePipe!");
lock (syncstate)
{
ts = DateTime.Now - last_heartbeat_time;
}
if (ts.TotalSeconds > 2 * 60)
{
Face.release();
logger.Info("Ready to Restart Myself!");
Thread.Sleep(200);
System.Windows.Forms.Application.Restart();
System.Environment.Exit(0);
}
Thread.Sleep(_namepipe_in_milisecond);
}
}
catch (Exception ex)
{
logger.Error("FaceOfflineRest.ThreadRestart:异常:" + ex.Message); ;
}
}
/// <summary>
/// 命名管道线程
/// </summary>
private static void ThreadNamePipe()
{
try
{
_pipe = new NamedPipeClientStream
(
".",
PipeName,
PipeDirection.InOut,
PipeOptions.Asynchronous | PipeOptions.WriteThrough
);
//logger.Info("NamePipeClient:Ready to Connect to pipe.");
_pipe.Connect();
//logger.Info("NamePipeClient:Connected to pipe.");
while (_namepiperunflag)
{
if (!_pipe.IsConnected)
{
_pipe = new NamedPipeClientStream
(
".",
PipeName,
PipeDirection.InOut,
PipeOptions.Asynchronous | PipeOptions.WriteThrough
);
//logger.Info("NamePipeClient:Again Ready to Connect to pipe.");
_pipe.Connect();
//logger.Info("NamePipeClient:Again Connected to pipe.");
}
using (StreamReader sr = new StreamReader(_pipe))
{
// Display the read text to the console
string temp;
while ((temp = sr.ReadLine()) != null)
{
//logger.Info("NamePipeClient:Received from server: {0}", temp);
if (temp == "myheartbeat")
{
lock (syncstate)
{
last_heartbeat_time = DateTime.Now;
}
}
}
}
}
}
catch (Exception ex)
{
logger.Error("FaceOfflineRest.ThreadNamePipe:异常:" + ex.Message);
}
}
#endregion
5.以上