一、添加Windows服务MainService
MainService.cs
using SuperSocket.SocketBase; using SuperSocket.SocketEngine; using System.ServiceProcess; namespace GpsTuQiangServiceDemo { partial class MainService : ServiceBase { private IBootstrap m_Bootstrap; public MainService() { InitializeComponent(); m_Bootstrap = BootstrapFactory.CreateBootstrap(); } protected override void OnStart(string[] args) { if (!m_Bootstrap.Initialize()) return; m_Bootstrap.Start(); } protected override void OnStop() { m_Bootstrap.Stop(); base.OnStop(); } protected override void OnShutdown() { m_Bootstrap.Stop(); base.OnShutdown(); } } }
二、添加安装程序类SocketServiceInstaller
SocketServiceInstaller.cs
using System.Collections.Generic; using System.ComponentModel; using System.Configuration; using System.Configuration.Install; using System.ServiceProcess; namespace GpsTuQiangServiceDemo { [RunInstaller(true)] public partial class SocketServiceInstaller : System.Configuration.Install.Installer { private ServiceInstaller serviceInstaller; private ServiceProcessInstaller processInstaller; public SocketServiceInstaller() { InitializeComponent(); processInstaller = new ServiceProcessInstaller(); serviceInstaller = new ServiceInstaller(); processInstaller.Account = ServiceAccount.LocalSystem; serviceInstaller.StartType = ServiceStartMode.Automatic; serviceInstaller.ServiceName = ConfigurationManager.AppSettings["ServiceName"]; var serviceDisplayName = ConfigurationManager.AppSettings["ServiceDisplayName"]; if (!string.IsNullOrEmpty(serviceDisplayName)) serviceInstaller.DisplayName = serviceDisplayName; var serviceDescription = ConfigurationManager.AppSettings["ServiceDescription"]; if (!string.IsNullOrEmpty(serviceDescription)) serviceInstaller.Description = serviceDescription; var servicesDependedOn = new List<string> { "tcpip" }; var servicesDependedOnConfig = ConfigurationManager.AppSettings["ServicesDependedOn"]; if (!string.IsNullOrEmpty(servicesDependedOnConfig)) servicesDependedOn.AddRange(servicesDependedOnConfig.Split(new char[] { ',', ';' })); serviceInstaller.ServicesDependedOn = servicesDependedOn.ToArray(); var serviceStartAfterInstall = ConfigurationManager.AppSettings["ServiceStartAfterInstall"]; if (!string.IsNullOrEmpty(serviceStartAfterInstall) && serviceStartAfterInstall.ToLower() == "true") this.AfterInstall += new InstallEventHandler(ProjectInstaller_AfterInstall); Installers.Add(serviceInstaller); Installers.Add(processInstaller); } private void ProjectInstaller_AfterInstall(object sender, InstallEventArgs e) { ServiceController sc = new ServiceController(serviceInstaller.ServiceName); sc.Start(); } } }
三、添加自安装类SelfInstaller
using System.Configuration.Install; using System.Reflection; namespace GpsTuQiangServiceDemo { public static class SelfInstaller { private static readonly string _exePath = Assembly.GetExecutingAssembly().Location; public static bool InstallMe() { try { ManagedInstallerClass.InstallHelper(new string[] { _exePath }); } catch { return false; } return true; } public static bool UninstallMe() { try { ManagedInstallerClass.InstallHelper(new string[] { "/u", _exePath }); } catch { return false; } return true; } } }
四、程序入口调用服务
using SuperSocket.Common; using SuperSocket.SocketBase; using SuperSocket.SocketEngine; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.ServiceProcess; namespace GpsTuQiangServiceDemo { class Program { private static bool setConsoleColor; private static Dictionary<string, ControlCommand> m_CommandHandlers = new Dictionary<string, ControlCommand>(StringComparer.OrdinalIgnoreCase); static void Main(string[] args) { string exeArg = string.Empty; if ((!Platform.IsMono && !Environment.UserInteractive)//Windows Service || (Platform.IsMono && !AppDomain.CurrentDomain.FriendlyName.Equals(Path.GetFileName(Assembly.GetEntryAssembly().CodeBase))))//MonoService { RunAsService(); return; } if (args == null || args.Length < 1) { Console.WriteLine("Welcome to GpsTuQiangServiceDemo!"); Console.WriteLine("Please press a key to continue..."); Console.WriteLine("-[r]: Run this application as a console application;"); Console.WriteLine("-[i]: Install this application as a Windows Service;"); Console.WriteLine("-[u]: Uninstall this Windows Service application;"); while (true) { exeArg = Console.ReadKey().KeyChar.ToString(); Console.WriteLine(); if (Run(exeArg, null)) break; } } else { exeArg = args[0]; if (!string.IsNullOrEmpty(exeArg)) exeArg = exeArg.TrimStart('-'); Run(exeArg, args); } } private static bool Run(string exeArg, string[] startArgs) { switch (exeArg.ToLower()) { case ("i"): SelfInstaller.InstallMe(); return true; case ("u"): SelfInstaller.UninstallMe(); return true; case ("r"): RunAsConsole(); return true; default: Console.WriteLine("Invalid argument!"); return false; } } static void CheckCanSetConsoleColor() { try { Console.ForegroundColor = ConsoleColor.Green; Console.ResetColor(); setConsoleColor = true; } catch { setConsoleColor = false; } } private static void SetConsoleColor(ConsoleColor color) { if (setConsoleColor) Console.ForegroundColor = color; } static void RunAsConsole() { Console.WriteLine("Welcome to GpsTuQiangServiceDemo!"); CheckCanSetConsoleColor(); Console.WriteLine("Initializing..."); IBootstrap bootstrap = BootstrapFactory.CreateBootstrap(); if (!bootstrap.Initialize()) { SetConsoleColor(ConsoleColor.Red); Console.WriteLine("Failed to initialize SuperSocket ServiceEngine! Please check error log for more information!"); Console.ReadKey(); return; } Console.WriteLine("Starting..."); var result = bootstrap.Start(); Console.WriteLine("-------------------------------------------------------------------"); foreach (var server in bootstrap.AppServers) { if (server.State == ServerState.Running) { SetConsoleColor(ConsoleColor.Green); Console.WriteLine("- {0} has been started", server.Name); } else { SetConsoleColor(ConsoleColor.Red); Console.WriteLine("- {0} failed to start", server.Name); } } Console.ResetColor(); Console.WriteLine("-------------------------------------------------------------------"); switch (result) { case (StartResult.None): SetConsoleColor(ConsoleColor.Red); Console.WriteLine("No server is configured, please check you configuration!"); Console.ReadKey(); return; case (StartResult.Success): Console.WriteLine("The SuperSocket ServiceEngine has been started!"); break; case (StartResult.Failed): SetConsoleColor(ConsoleColor.Red); Console.WriteLine("Failed to start the SuperSocket ServiceEngine! Please check error log for more information!"); Console.ReadKey(); return; case (StartResult.PartialSuccess): SetConsoleColor(ConsoleColor.Red); Console.WriteLine("Some server instances were started successfully, but the others failed! Please check error log for more information!"); break; } Console.ResetColor(); Console.WriteLine("Enter key 'quit' to stop the ServiceEngine."); RegisterCommands(); ReadConsoleCommand(bootstrap); bootstrap.Stop(); Console.WriteLine("The SuperSocket ServiceEngine has been stopped!"); } static void ReadConsoleCommand(IBootstrap bootstrap) { var line = Console.ReadLine(); if (string.IsNullOrEmpty(line)) { ReadConsoleCommand(bootstrap); return; } if ("quit".Equals(line, StringComparison.OrdinalIgnoreCase)) return; var cmdArray = line.Split(' '); if (!m_CommandHandlers.TryGetValue(cmdArray[0], out ControlCommand cmd)) { Console.WriteLine("Unknown command"); ReadConsoleCommand(bootstrap); return; } try { if (cmd.Handler(bootstrap, cmdArray)) Console.WriteLine("Ok"); } catch (Exception e) { Console.WriteLine("Failed. " + e.Message + Environment.NewLine + e.StackTrace); } ReadConsoleCommand(bootstrap); } private static void AddCommand(string name, string description, Func<IBootstrap, string[], bool> handler) { var command = new ControlCommand { Name = name, Description = description, Handler = handler }; m_CommandHandlers.Add(command.Name, command); } static bool ListCommand(IBootstrap bootstrap, string[] arguments) { foreach (var s in bootstrap.AppServers) { if (s is IProcessServer processInfo && processInfo.ProcessId > 0) Console.WriteLine("{0}[PID:{1}] - {2}", s.Name, processInfo.ProcessId, s.State); else Console.WriteLine("{0} - {1}", s.Name, s.State); } return false; } static bool StartCommand(IBootstrap bootstrap, string[] arguments) { var name = arguments[1]; if (string.IsNullOrEmpty(name)) { Console.WriteLine("Server name is required!"); return false; } var server = bootstrap.AppServers.FirstOrDefault(s => s.Name.Equals(name, StringComparison.OrdinalIgnoreCase)); if (server == null) { Console.WriteLine("The server was not found!"); return false; } server.Start(); return true; } static bool StopCommand(IBootstrap bootstrap, string[] arguments) { var name = arguments[1]; if (string.IsNullOrEmpty(name)) { Console.WriteLine("Server name is required!"); return false; } var server = bootstrap.AppServers.FirstOrDefault(s => s.Name.Equals(name, StringComparison.OrdinalIgnoreCase)); if (server == null) { Console.WriteLine("The server was not found!"); return false; } server.Stop(); return true; } private static void RegisterCommands() { AddCommand("List", "List all server instances", ListCommand); AddCommand("Start", "Start a server instance: Start {ServerName}", StartCommand); AddCommand("Stop", "Stop a server instance: Stop {ServerName}", StopCommand); } static void RunAsService() { ServiceBase[] servicesToRun; servicesToRun = new ServiceBase[] { new MainService() }; ServiceBase.Run(servicesToRun); } } }