将exe程序做成进程服务
说明
- 本次使用的开发语言为C#
- 借助服务安装工具为nssm(C++开发的)
对Nssm进行一个简单的封装
using System.Diagnostics;
using System.Text;
using System.Threading.Channels;
using Model.Enums;
namespace Nssm;
public static class NssmExeHelper
{
private static string NssmExeFile { get; set; }
static NssmExeHelper()
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
const string baseDir = @"NssmExe";
NssmExeFile = Path.Combine(baseDir, Environment.Is64BitOperatingSystem ? @"win64\nssm.exe" : @"win32\nssm.exe");
}
/// <summary>
/// 加载自定义nssm执行程序
/// </summary>
/// <param name="nssmExe"></param>
public static void LoadNssmExe(string nssmExe)
{
NssmExeFile = nssmExe;
}
private static Process Create()
{
var process = new Process();
process.StartInfo.UseShellExecute = false;
process.StartInfo.FileName = NssmExeFile;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardError = true;
return process;
}
public static bool InstallService(string serviceName, string exeFile, string param = "")
{
if (GetServiceStatus(serviceName) != ServiceStatusEnum.NotInstalled) return false;
var process = Create();
process.StartInfo.Arguments = $" install {serviceName} {exeFile} {param}";
process.Start();
var msg = process.StandardOutput.ReadLine();
if (string.IsNullOrEmpty(msg))
{
// var errorMsg = process.StandardError.ReadLine()?.Replace("\0", "");
// throw new Exception(errorMsg);
return false;
}
Console.WriteLine(msg.Replace("\0", ""));
process.Close();
return true;
}
public static void RemoveService(string serviceName)
{
var process = Create();
process.StartInfo.Arguments = $" remove {serviceName} confirm";
process.Start();
var msg = process.StandardOutput.ReadLine();
if (string.IsNullOrEmpty(msg))
{
var errorMsg = process.StandardError.ReadLine()?.Replace("\0", "");
throw new Exception(errorMsg);
}
Console.WriteLine(msg.Replace("\0", ""));
process.Close();
}
/// <summary>
/// 启动服务
/// </summary>
/// <param name="serviceName"></param>
/// <param name="errMsg"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public static bool StartService(string serviceName, out string errMsg)
{
errMsg = string.Empty;
var status = GetServiceStatus(serviceName);
if (status == ServiceStatusEnum.NotInstalled) throw new Exception("服务未安装");
if (status == ServiceStatusEnum.Stopped)
{
return ServiceHandle("start", serviceName, out errMsg);
}
if (status == ServiceStatusEnum.Running)
{
return true;
}
errMsg = $"当前服务状态未停止:{status}";
return false;
}
/// <summary>
/// 停止服务
/// </summary>
/// <param name="serviceName"></param>
/// <param name="errMsg"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public static bool StopService(string serviceName, out string errMsg)
{
errMsg = string.Empty;
var status = GetServiceStatus(serviceName);
if (status == ServiceStatusEnum.NotInstalled) throw new Exception("服务未安装");
if (status == ServiceStatusEnum.Running)
{
return ServiceHandle("stop", serviceName, out errMsg);
}
if (status == ServiceStatusEnum.Stopped)
{
return true;
}
errMsg = $"当前服务状态:{status}";
return false;
}
/// <summary>
/// 服务执行核心逻辑
/// </summary>
/// <param name="cmd"></param>
/// <param name="serviceName"></param>
/// <param name="resultMsg"></param>
/// <returns></returns>
private static bool ServiceHandle(string cmd, string serviceName, out string resultMsg)
{
resultMsg = string.Empty;
var process = Create();
process.StartInfo.Arguments = $" {cmd} {serviceName} ";
process.Start();
var msg = process.StandardOutput.ReadLine();
if (string.IsNullOrEmpty(msg))
{
var errorMsg = process.StandardError.ReadLine()?.Replace("\0", "");
resultMsg = errorMsg!;
return false;
}
resultMsg = msg.Replace("\0", "");
process.Close();
return true;
}
/// <summary>
/// 查看服务运行状态
/// </summary>
/// <param name="serviceName"></param>
/// <param name="resultMsg"></param>
/// <returns></returns>
private static bool LookServiceStatus(string serviceName, out string resultMsg)
{
return ServiceHandle("status", serviceName, out resultMsg);
}
/// <summary>
/// 获取服务状态
/// </summary>
/// <param name="serviceName"></param>
/// <returns></returns>
public static ServiceStatusEnum GetServiceStatus(string serviceName)
{
if (!LookServiceStatus(serviceName, out var msg)) return ServiceStatusEnum.NotInstalled;
switch (msg.ToLower())
{
case "service_stopped":
return ServiceStatusEnum.Stopped;
case "service_running":
return ServiceStatusEnum.Running;
case "service_paused":
return ServiceStatusEnum.Paused;
default:
return ServiceStatusEnum.UnknownError;
}
}
/// <summary>
/// 设置服务的控制台输入重定向到文件
/// </summary>
/// <param name="serviceName"></param>
/// <param name="stdOutLog"></param>
/// <param name="stdErrLog"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public static bool SetServiceOutLog(string serviceName, string stdOutLog, string stdErrLog)
{
var status = GetServiceStatus(serviceName);
if (status == ServiceStatusEnum.NotInstalled) throw new Exception("服务未安装");
var process = Create();
process.StartInfo.Arguments = $" set {serviceName} AppStdout {stdOutLog} ";
process.Start();
process.StartInfo.Arguments = $" set {serviceName} AppStderr {stdErrLog}";
process.Start();
process.Close();
return true;
}
}
服务状态的枚举类
/// <summary>
/// 服务状态枚举
/// </summary>
public enum ServiceStatusEnum : byte
{
UnknownError,
NotInstalled,
Stopped,
Running,
Paused,
}