标签:
Windows 服务是可以在系统启动时自动打开的程序。如果需要在没有用户交互操作情况下运行程序,或者在权限比交互式用户更大的用户下运行程序,就可以创建 Windows 服务。
操作 Windows 服务需要3种程序:
• 服务程序
• 服务控制程序
• 服务配置程序
服务程序本身用于提供需要的实际功能。
服务控制程序可以把控制请求发送给服务,如开始、停止、暂停和继续。
使用服务配置程序可以安装服务,也可以在以后改变服务的配置。
服务程序实现服务的功能。服务程序需要 3 个部分:
• 主函数
• service-main 函数
• 处理程序
服务的主函数是程序的一般入口点,即Main()方法,它可以注册多个 service-main 函数,service-main 函数包含服务的实际功能。服务必须为所提供的每项服务注册一个 service-main 函数。
可以在System.ServiceProcess名称空间中找到实现服务的 3 部分的服务类:
• 必须从 ServiceBase 类继承才能实现服务。ServiceBase 类用于注册服务、响应开始和停止请求。
• ServiceController类用于实现服务控制程序。使用这个类,可以把请求发送给服务。
• ServiceProcessInstaller类和ServiceInstaller类用于安装和配置服务程序。
实例程序对于客户发出的每一个请求,引用服务器都返回引用文件的一个随机引用。解决方案由 3 个程序集完成,一个用户客户端,两个用于服务器。
QuoteServer 类库包含实际的功能,QuoteClient 是 WPF 胖客户端应用程序,这个应用程序创建客户端套接字,以便与 Quote Server 进行通信。第三个程序集是实际的服务。Quote Service 开始和停止 QuoteServer,服务将控制服务器。
QuoteServer.cs
1 using System; 2 using System.Collections.Generic; 3 using System.Diagnostics; 4 using System.Diagnostics.Contracts; 5 using System.IO; 6 using System.Linq; 7 using System.Net; 8 using System.Net.Sockets; 9 using System.Text; 10 using System.Threading.Tasks; 11 12 namespace QuoteService 13 { 14 public class QuoteServer 15 { 16 private TcpListener listener; 17 private int port; 18 private string filename; 19 private List<string> quotes; 20 private Random random; 21 private Task listenerTask; 22 23 public QuoteServer() 24 :this("quotes.txt") 25 { 26 } 27 28 public QuoteServer(string filename) 29 : this(filename, 7890) 30 { 31 } 32 33 public QuoteServer(string filename, int port) 34 { 35 Contract.Requires<ArgumentNullException>(filename != null); 36 Contract.Requires<ArgumentException>(port >= IPEndPoint.MinPort && 37 port <= IPEndPoint.MaxPort); 38 this.filename = filename; 39 this.port = port; 40 } 41 42 protected void ReadQuotes() 43 { 44 try 45 { 46 quotes = File.ReadAllLines(filename).ToList(); 47 if (quotes.Count == 0) 48 { 49 throw new QuoteException("quote file is empty"); 50 } 51 random = new Random(); 52 } 53 catch (IOException ex) 54 { 55 throw new QuoteException("I/O Error",ex); 56 } 57 } 58 59 protected string GetRandomQuoteOfTheDay() 60 { 61 var index = random.Next(0, quotes.Count); 62 return quotes[index]; 63 } 64 65 protected void Listener() 66 { 67 try 68 { 69 IPAddress ipAddress = IPAddress.Any; 70 listener = new TcpListener(ipAddress, port); 71 listener.Start(); 72 while (true) 73 { 74 Socket clientSocket = listener.AcceptSocket(); 75 string message = GetRandomQuoteOfTheDay(); 76 var encoder = new UnicodeEncoding(); 77 byte[] buffer = encoder.GetBytes(message); 78 clientSocket.Send(buffer, buffer.Length, 0); 79 clientSocket.Close(); 80 } 81 } 82 catch (SocketException ex) 83 { 84 Trace.TraceError($"QuoteServer {ex.Message}"); 85 throw new QuoteException("socket error",ex); 86 } 87 } 88 89 #region 控制 90 91 public void Start() 92 { 93 ReadQuotes(); 94 listenerTask = Task.Factory.StartNew(Listener, 95 TaskCreationOptions.LongRunning); 96 } 97 98 public void Stop() 99 { 100 listener.Stop(); 101 } 102 103 public void Suspend() 104 { 105 listener.Stop(); 106 } 107 108 public void Resume() 109 { 110 Start(); 111 } 112 113 #endregion 114 115 public void RefreshQuotes() 116 { 117 ReadQuotes(); 118 } 119 120 } 121 122 [Serializable] 123 public class QuoteException : Exception 124 { 125 public QuoteException() { } 126 public QuoteException(string message) : base(message) { } 127 public QuoteException(string message, Exception inner) : base(message, inner) { } 128 protected QuoteException( 129 System.Runtime.Serialization.SerializationInfo info, 130 System.Runtime.Serialization.StreamingContext context) 131 : base(info, context) { } 132 } 133 }
创建测试程序并调用 QuoteServer 类的 Start() 方法,测试程序是一个 C#控制台应用程序TestQuoteServer,并引用QuoteServer类的程序集。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace QuoteService { class Program { static void Main(string[] args) { var qs = new QuoteServer("quotes.txt", 7890); qs.Start(); Console.WriteLine("Hit return to exit"); Console.ReadLine(); qs.Stop(); } } }
胖客户端代码:
QuoteInformation.cs
using System.Collections.Generic; using System.ComponentModel; using System.Runtime.CompilerServices; namespace QuoteClient { public class QuoteInformation:INotifyPropertyChanged { public QuoteInformation() { EnableRequest = true; } private string quote; public string Quote { get { return quote; } internal set { SetProperty(ref quote, value); } } private bool enableRequest; public bool EnableRequest { get { return enableRequest; } internal set { SetProperty(ref enableRequest, value); } } private void SetProperty<T>(ref T field, T value,[CallerMemberName] string propertyName="") { if (!EqualityComparer<T>.Default.Equals(field, value)) { field = value; var handler = PropertyChanged; if (handler != null) { handler(this,new PropertyChangedEventArgs(propertyName)); } } } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }
MainWindow.xaml
<TextBlock x:Name="textBlock" HorizontalAlignment="Left" Margin="111,103,0,0" TextWrapping="Wrap" Text="{Binding Quote}" VerticalAlignment="Top" Height="144" Width="277"/> <Button x:Name="button" Content="Button" HorizontalAlignment="Left" Margin="216,47,0,0" VerticalAlignment="Top" Width="75" IsEnabled="{Binding EnableRequest}" Click="OnGetQuote"/>
MainWindow.xaml.cs
using System.Net.Sockets; using System.Text; using System.Windows; using System.Windows.Input; namespace QuoteClient { /// <summary> /// MainWindow.xaml 的交互逻辑 /// </summary> public partial class MainWindow : Window { private QuoteInformation quoteInfo = new QuoteInformation(); public MainWindow() { InitializeComponent(); this.DataContext = quoteInfo; } protected async void OnGetQuote(object sender, RoutedEventArgs e) { const int bufferSize = 1024; Cursor currentCursor = this.Cursor; this.Cursor = Cursors.Wait; quoteInfo.EnableRequest = false; string serverName = Properties.Settings.Default.ServerName; int port = Properties.Settings.Default.PortNumber; var client = new TcpClient(); NetworkStream stream = null; try { await client.ConnectAsync(serverName, port); stream = client.GetStream(); byte[] buffer = new byte[bufferSize]; int received = await stream.ReadAsync(buffer, 0, bufferSize); if (received <= 0) { return; } quoteInfo.Quote = Encoding.Unicode.GetString(buffer).Trim(‘\0‘); } catch (SocketException ex) { MessageBox.Show(ex.Message, "Error Quote of the day", MessageBoxButton.OK, MessageBoxImage.Error); throw; } finally { if (stream != null) { stream.Close(); } if (client.Connected) { client.Close(); } } this.Cursor = currentCursor; quoteInfo.EnableRequest = true; } } }
服务程序代码:
QuoteService.cs
using System; using System.IO; using System.ServiceProcess; namespace QuoteService { public partial class QuoteService : ServiceBase { private QuoteServer quoteServer; public QuoteService() { InitializeComponent(); } protected override void OnStart(string[] args) { quoteServer = new QuoteServer(Path.Combine( AppDomain.CurrentDomain.BaseDirectory,"quotes.txt")); quoteServer.Start(); } protected override void OnStop() { quoteServer.Stop(); } protected override void OnPause() { quoteServer.Suspend(); } protected override void OnContinue() { quoteServer.Resume(); } public const int commandRefresh = 128; protected override void OnCustomCommand(int command) { switch (command) { case commandRefresh: quoteServer.RefreshQuotes(); break; default: break; } } } }
Program.cs
using System.ServiceProcess; namespace QuoteService { static class Program { /// <summary> /// 应用程序的主入口点。 /// </summary> static void Main() { ServiceBase[] ServicesToRun; ServicesToRun = new ServiceBase[] { new QuoteService() }; ServiceBase.Run(ServicesToRun); } } }
服务类切到设计视图,右键菜单“添加安装程序”,就可以给服务添加安装程序。
标签:
原文地址:http://www.cnblogs.com/khjian/p/5903693.html