C#学习笔记 ----Windows服务(第25章)

操作Windows服务需要3种:

服务程序

服务控制程序

服务配置程序

服务程序需要3部分:主函数、service-main函数、处理程序

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;

namespace QuoteServer
{
    public class QuoteServer
    {
        private TcpListener listener;
        private int port;
        private string filename;
        private List<string> quotes;
        private Random random;
        private Thread listenerThread;

        public QuoteServer()
            : this("quotes.txt")
        {
        }

        public QuoteServer(string filename)
            : this(filename, 7890)
        {
        }

        public QuoteServer(string filename, int port)
        {
            this.filename = filename;
            this.port = port;
        }

        protected void ReadQuotes()
        {
            quotes = File.ReadAllLines(filename).ToList();
            random = new Random();
        }

        protected string GetRandomQuoteOfTheDay()
        {
            int index = random.Next(0,quotes.Count);
            return quotes[index];
        }

        public void Start()
        {
            ReadQuotes();
            listenerThread = new Thread(ListenerThread);
            listenerThread.IsBackground = true;
            listenerThread.Name = "Listener";
            listenerThread.Start();
        }

        protected void ListenerThread()
        {
            try
            {
                IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
                listener = new TcpListener(ipAddress, port);
                listener.Start();

                while (true)
                {
                    Socket clientSocket = listener.AcceptSocket();
                    string message = GetRandomQuoteOfTheDay();
                    UnicodeEncoding encoder = new UnicodeEncoding();
                    byte[] buffer = encoder.GetBytes(message);
                    clientSocket.Send(buffer, buffer.Length, 0);
                    clientSocket.Close();
                }
            }
            catch (SocketException ex)
            {
                Trace.TraceError(string.Format("QuoteServer {0}",ex.Message));
            }
        }

        public void Stop()
        {
            listener.Stop();
        }

        public void Suspend()
        {
            listener.Stop();
        }

        public void Resume()
        {
            Start();
        }

        public void RefreshQuotes()
        {
            ReadQuotes();
        }
    }
}

服务控制管理器(Servcie Control Manager,SCM)

SCM是操作系统的一个组成部分,它的作用是与服务进行通信

服务负责为它的每一个服务都注册一个service-main函数。

service-main函数一个重要任务是用SCM注册一个处理程序

处理程序必须响应SCM的事件

服务控制程序可以把停止、暂停和继续服务的请求发送给SCM

服务控制程序独立于SCM和服务本身

System.ServiceProcess名称空间中实现服务的3部分的服务类:

必须从ServiceBase类继承才可以实现服务

ServiceController类用于实现服务控制程序

ServiceProcessInstaller类和ServiceInstaller类用于安装和配置服务程序

ServiceBase类是所有用.NET Framework开发的Windows服务的基类

ServiceBase基类的Run()方法,使用SCM中NativeMethods.StartServiceCtrlDispather()方法注册ServiceMainCallback()方法,并把记录写到事件日志中

处理程序在ServiceCommandCallback()方法中执行

当改变了对服务的请求时,SCM调用ServiceCommandCallback()方法

ServiceCommandCallback()方法再把请求发送给OnPause()、OnContinue()、OnStop ()、OnCustomCommand()和OnPowerEvent()

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceProcess;
using System.Text;

namespace QuoteServer
{
    static class Program
    {
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        static void Main()
        {
            ServiceBase[] ServicesToRun;
            ServicesToRun = new ServiceBase[]
            {
                new QuoteServer()
            };
            ServiceBase.Run(ServicesToRun);
        }
    }
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;

namespace QuoteServer
{
    public partial class QuoteServer : ServiceBase
    {
        public QuoteServer()
        {
            InitializeComponent();
        }

        protected override void OnStart(string[] args)
        {
        }

        protected override void OnStop()
        {
        }
    }
}

服务的设计视图,右键添加安装程序

新建一个ProjectInstaller类、一个ServiceInstaller实例和一个ServiceProcessInstaller实例

namespace QuoteServer
{
    partial class ProjectInstaller
    {
        /// <summary>
        /// 必需的设计器变量。
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// 清理所有正在使用的资源。
        /// </summary>
        /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region 组件设计器生成的代码

        /// <summary>
        /// 设计器支持所需的方法 - 不要
        /// 使用代码编辑器修改此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {
            this.serviceProcessInstaller1 = new System.ServiceProcess.ServiceProcessInstaller();
            this.serviceInstaller1 = new System.ServiceProcess.ServiceInstaller();
            //
            // serviceProcessInstaller1
            //
            this.serviceProcessInstaller1.Password = null;
            this.serviceProcessInstaller1.Username = null;
            //
            // serviceInstaller1
            //
            this.serviceInstaller1.ServiceName = "Service1";
            //
            // ProjectInstaller
            //
            this.Installers.AddRange(new System.Configuration.Install.Installer[] {
            this.serviceProcessInstaller1,
            this.serviceInstaller1});

        }

        #endregion

        private System.ServiceProcess.ServiceProcessInstaller serviceProcessInstaller1;
        private System.ServiceProcess.ServiceInstaller serviceInstaller1;
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.Linq;

namespace QuoteServer
{
    [RunInstaller(true)]
    public partial class ProjectInstaller : System.Configuration.Install.Installer
    {
        public ProjectInstaller()
        {
            InitializeComponent();
        }
    }
}

installutil.exe实用程序安装和卸载服务

installutil quoteservice.exe

installutil /u quoteservice.exe

Service MMC管理单元对服务进行监视和控制

net.exe 可以控制服务

sc.exe 命令行实用程序

时间: 2024-10-11 06:38:56

C#学习笔记 ----Windows服务(第25章)的相关文章

Symfony2 学习笔记之服务容器

现在的PHP应用程序都是面向对象开发,所以主要是由对象构成.有的对象可以方便的分发邮件信息而有的可能帮你把信息写入到数据库中.在你的应用程序中,你可能创建一个对象用于管理你的产品库存,或者另外一个对象处理来自第三方API的数据.重要的是现在应用程序要做的这些事情都是被组织到许许多多的对象中来处理它的每一项任务的. 我们将套路一下Symfony2中一个特殊的PHP对象,它帮助我们实例化,组织和获取你应用程序汇总的许多对象.这个对象叫做服务容器,它可以帮助你使用标准统一的方式来创建你程序中的对象.它

《python基础教程(第二版)》学习笔记 字符串(第3章)

<python基础教程(第二版)>学习笔记 字符串(第3章)所有的基本的序列操作(索引,分片,乘法,判断成员资格,求长度,求最大最小值)对字符串也适用.字符串是不可以改变的:%左侧是格式字符串,右侧是需要格式化的值print '%s=%d' % ('x',100) ==> x=100%% 格式字符串中出现 %模板字符串:from string import Templates=Template('$x is 100');  s.substitute(x='ABC');  ==> '

《python基础教程(第二版)》学习笔记 字典(第4章)

<python基础教程(第二版)>学习笔记 字典(第4章)创建字典:d={'key1':'value1','key2':'value2'}lst=[('key1','value1'),('key2','value2')]; d=dict(lst)d=dict(key1='value1', key2='value2')字典基本操作:d={'key1':'value1','key2':'value2'}; len(d) ==> 2 #字典中的键值对数量d={'key1':'value1','

DirectX 11游戏编程学习笔记之7: 第6章Drawing in Direct3D(在Direct3D中绘制)(重点回顾+勘误)

        本文由哈利_蜘蛛侠原创,转载请注明出处!有问题欢迎联系[email protected]         注:我给的电子版是700多页,而实体书是800多页,所以我在提到相关概念的时候,会使用章节号而非页码.同样的情况适合于"龙书"第二版. 上一期的地址: DX 11游戏编程学习笔记之6 这一章应该是本书最长的一章了,可能也是最难的一章,所以大家一定要好好消化,仔细学习!这一章大致相当于"龙书"第二版的第7章和第8章,还添加了一些别的东西. 由于这一

&lt;深入理解C指针&gt;学习笔记和总结 第四章 指针和数组

数组是一个什么玩意: 数组和指针我的理解,有相同之处也有不同之处.因有相同之处,因此一些资料上说,数组和指针本质是相同的.因有不同之处,因此也有一些资料上说,数组和指针是不一样的. 相同之处: 数组名字和指针名字都代表了一个地址. 如:int num[10];num是数组名.函数开辟了一个存储十个整数类型的空间,而num是他们的首地址. int *p; p=(int *)malloc(10*sizeof(int));类似的,p也指向了首地址. 不同之处是,num[10]中的空间位置是在栈中,而

UNP学习笔记(第十五章 UNIX域协议)

UNIX域协议是在单个主机上执行客户/服务器通信的一种方法 使用UNIX域套接字有以下3个理由: 1.UNIX域套接字往往比通信两端位于同一个主机的TCP套接字快出一倍 2.UNIX域套接字可用于在同一个主机上的不同进程之间传递描述符 3.UNIX域套接字较新的实现把客户的凭证提供给服务器,从而能够提供额外的安全检查措施 UNIX域中用于标识客户和服务器的协议地址是普通文件系统的路径名.这些路径名不是普通的UNIX文件: 除非他们和UNIX域套接字关联起来,否则无法读写这些文件. 可以查看之前a

Dubbo -- 系统学习 笔记 -- 示例 -- 服务分组

Dubbo -- 系统学习 笔记 -- 目录 示例 想完整的运行起来,请参见:快速启动,这里只列出各种场景的配置方式 服务分组 当一个接口有多种实现时,可以用group区分. <dubbo:service group="feedback" interface="com.xxx.IndexService" /> <dubbo:service group="member" interface="com.xxx.IndexS

apue学习笔记(第十六章 网络IPC:套接字)

本章将考察不同计算机(通过网络连接)上的进程相互通信的机制:网络进程间通信. 套接字描述符 正如使用文件描述符访问文件,应用程序用套接字描述符访问套接字. 许多处理文件描述符函数(如read和write)可以用于处理套接字描述符.调用socket函数创建一个套接字 #include <sys/socket.h> int socket(int domain,int type,int protocol); 参数domain(域)确定通信的特性,包括地址格式.下图总结了POSIX.1指定的各个域,每

(二)Netty学习笔记之服务端启动

本文将不会对netty中每个点分类讲解,而是一个服务端启动的代码走读,在这个过程中再去了解和学习,这也是博主自己的学习历程.下面开始正文~~~~ 众所周知,在写netty服务端应用的时候一般会有这样的启动代码: (代码一) 1 EventLoopGroup bossGroup = new NioEventLoopGroup(1); 2 EventLoopGroup workerGroup = new NioEventLoopGroup(); 3 try { 4 ServerBootstrap b