zoukankan      html  css  js  c++  java
  • C#开发系统服务时用的定时器组件

    写服务时,都需要为定时器写不少的代码,感觉很麻烦,今天把这些代码封装一下,希望能简化一下这方面的工作,把精力都集中在功能上

    本定时器组件,每次只启动一个服务实例进行处理,而不会同时多次执行服务代码。

    下面是应用实例

    从组件类派生一个子类,可以看到,需要写的代码很少

    using System;   
    using System.Collections.Generic;   
    using System.IO;   
    using System.Text.RegularExpressions;   
    using System.Threading;
      
    namespace BlueVision.SaYuan.WinService   
    {   
        public class TestService : ServiceTimerContorl   
        {   
            protected override void StartService()   
            {   
                //需要做的事情的代码   
            }   
      
            protected override ServiceTimeConfig GetTimerConfig()   
            {   
                ServiceTimeConfig config = new ServiceTimeConfig();   
      
                // 如果该枚举是选择 Interval ,则表示,上述的 StartService 方法,将隔 config.ChkInterval 毫秒执行一次   
                config.TimerMode = TimerMode.Interval;   
                config.ChkInterval = 100000;   
      
      
                /// StartTime值为:   
                ///    
                /// TimerMode=TimerMode.Month   "09|04:30"  -表示每月9号的凌晨4点30分   
                /// TimerMode=TimerMode.Week     "0|04:30"  -表示每星期天的4点30分   
                /// TimerMode=TimerMode.Week     "6|04:00"  -表示每星期6的4点30分   
                /// TimerMode=TimerMode.Day       "|04:00"  -表示每天的4点00分   
                /// TimerMode=TimerMode.Date "08-10|04:00"  -表示每年8月10号的4点00分执行一次   
                /// TimerMode=TimerMode.Year   "246|04"     -表示每年第246天的4点00分执行一次(可以不填写分钟默认为00)   
      
                //如果是这样设置 则表示,每天的凌晨 4 点 00 执行一次   
                config.TimerMode = TimerMode.Day;   
                config.StartTime = "|04";   
      
                //如果是这样设置 则表示,每个星期的星期四那天的凌晨 6 点 35 执行一次   
                config.TimerMode = TimerMode.Week;   
                config.StartTime = "4|06:35";   
      
                //如果是这样设置 则表示,每个星期的星期天那天的凌晨 6 点 00 执行一次   
                config.TimerMode = TimerMode.Week;   
                config.StartTime = "0|06";   
      
                //如果是这样设置 则表示,每个月的9号凌晨 6 点 28 执行一次   
                config.TimerMode = TimerMode.Month;   
                config.StartTime = "09|06:28";   
      
                //如果是这样设置 则表示,每年8月10号的4点00分执行一次   
                config.TimerMode = TimerMode.Date;   
                config.StartTime = "08-10|04:00";   
      
                //如果是这样设置 则表示,每年第246天的4点27分执行一次   
                config.TimerMode = TimerMode.Year;   
                config.StartTime = "246|04:27";   
      
                return config;   
            }   
            /// <summary>   
            /// 当服务出错时,处理   
            /// </summary>   
            /// <param name="ex"></param>   
            protected override void  ServiceException(Exception ex)   
            {   
                 //可以不实现   
            }   
        }   
    }   
      
      
    //要执行代码,以下这样就可以了
    TestService testService = new TestService();   
    testService.Start(); 

    以下是组件的源代码

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Text.RegularExpressions;
    using System.Threading;
    
    namespace BlueVision.SaYuan.WinService
    {
        /// <summary>
        /// 服务定时器管理
        /// </summary>
        public abstract class ServiceTimerControl
        {
            #region 私有成员
            /// <summary>
            /// 定时器
            /// </summary>
            private Timer SysTimer { get; set; }
            /// <summary>
            /// 是否启用定时器
            /// </summary>
            private bool _EnabledTimer = true;
            /// <summary>
            /// 服务执行状态
            /// </summary>
            private ServiceStatus _serviceStatus = ServiceStatus.Sleep;
            /// <summary>
            /// 时间计算类
            /// </summary>
            private TimerControl _timerControl = null;
            /// <summary>
            /// 定时器配置
            /// </summary>
            ServiceTimeConfig Config;
            #endregion
    
            #region 公共属性
            /// <summary>
            /// 获取服务状态
            /// </summary>
            public ServiceStatus ServiceStatus { get { return _serviceStatus; } }
            /// <summary>
            /// 计时模式
            /// </summary>
            public TimerMode TimerMode
            {
                get
                {
                    if ( Config == null ) Config = this.GetTimerConfig();
    
                    return Config.TimerMode;
                }
            }
            /// <summary>
            /// 计时配置
            /// </summary>
            public string StartTime { get { return ( Config == null ) ? "" : Config.StartTime; } }
            /// <summary>
            /// 时间计算类
            /// </summary>
            public TimerControl TimerControl
            {
                get
                {
                    if ( Config == null )
                        Config = this.GetTimerConfig();
                    if ( _timerControl == null )
                        _timerControl = new TimerControl( this.Config.StartTime, this.Config.TimerMode );
    
                    return _timerControl;
                }
            }
            #endregion
    
            /// <summary>
            /// 停止
            /// </summary>
            public void Stop()
            {
                _EnabledTimer = false;
    
                SysTimer.Change( Timeout.Infinite, Timeout.Infinite );
            }
            /// <summary>
            /// 开始服务
            /// </summary>
            public void Start()
            {
                _EnabledTimer = true;
                Config = this.GetTimerConfig();
    
                SysTimer = new Timer( new TimerCallback( this.TimerProcess ), AppDomain.CurrentDomain, 0, this.Config.ChkInterval );
            }
            /// <summary>
            /// 处理间隔服务
            /// </summary>
            /// <param name="sender"></param>
            private void TimerProcess( object sender )
            {
                if ( !_EnabledTimer ) return;
    
                bool TimeIsUp = true;
                if ( this.Config.TimerMode != TimerMode.Interval )
                {
                    // 如果定时方式不是定时轮询的话,就构造TimerControl类,该类用来计算每次执行完程序后
                    // 到下次执行服务时需要休眠的时间
                    try
                    {
                        _timerControl = new TimerControl( this.Config.StartTime, this.Config.TimerMode );
                        TimeIsUp = _timerControl.TimeIsUp;    // 获取是否到了执行服务程序的时间了
                    }
                    catch ( Exception ex )
                    {
                        // 读取配置出错且TimerControl对象已不存在,则再抛出异常
                        // 如果上一次读取配置成功,那就就算这次的配置有问题,则也不会停止程序的运行,仍用上一次的数据做为参数
                        if ( _timerControl == null ) throw ex;
                    }
                }
    
                try
                {
                    if ( TimeIsUp )// 时间到了可以执行程序了
                    {
                        // 服务运行了
                        _serviceStatus = ServiceStatus.Running;
    
                        // 设置计时器,在无穷时间后再启用(实际上就是永远不启动计时器了--停止计时器计时)
                        SysTimer.Change( Timeout.Infinite, this.Config.ChkInterval );
    
                        //开始处理服务
                        this.StartService();
                    }
                }
                catch ( Exception ex ) { this.ServiceException( ex ); }    // 处理服务执行过程中出现的异常
                finally
                {
                    // 如果计时器不为空,则重新设置休眠的时间
                    if ( SysTimer != null )
                    {
                        if ( this.Config.TimerMode == TimerMode.Interval )// 定时轮询设置
                        {
                            // 重新启用计时器
                            SysTimer.Change( this.Config.ChkInterval, this.Config.ChkInterval );
                        }
                        else// 定时设置
                        {
                            // 用cft类计算下一次到期的时间
                            TimeSpan Interval = _timerControl.GetNextTimeUp();
                            // 重新启用计时器
                            SysTimer.Change( Interval, Interval );
                        }
                    }
                    _serviceStatus = ServiceStatus.Sleep;
                }
            }
            /// <summary>
            /// 开始服务
            /// </summary>
            protected abstract void StartService();
            /// <summary>
            /// 定时器初始化
            /// </summary>
            /// <param name="TimerMode"></param>
            /// <param name="StartTime"></param>
            /// <param name="ChkInterval"></param>
            protected abstract ServiceTimeConfig GetTimerConfig();
            /// <summary>
            /// 系统服务错误
            /// </summary>
            /// <param name="ex"></param>
            protected virtual void ServiceException( Exception ex ) { return; }
        }
    
        #region 定时器相关实体类
        /// <summary>
        /// 服务定时器配置
        /// </summary>
        public class ServiceTimeConfig
        {
            /// <summary>
            /// 轮询目录时间间隔(单位:毫秒)
            /// </summary>
            public int ChkInterval { get; set; }
            /// <summary>
            /// StartTime值为:
            /// 
            /// TimerMode=TimerMode.Month    "09|04:30"    -表示每月9号的凌晨4点30分
            ///    TimerMode=TimerMode.Week     "0|04:30"    -表示每星期天的4点30分
            /// TimerMode=TimerMode.Week     "6|04:00"    -表示每星期6的4点30分
            ///    TimerMode=TimerMode.Day          "|04:00"    -表示每天的4点00分
            ///    TimerMode=TimerMode.Date "08-10|04:00"    -表示每年8月10号的4点00分执行一次
            ///    TimerMode=TimerMode.Year   "246|04"        -表示每年第246天的4点00分执行一次(可以不填写分钟默认为00)
            /// </summary>
            public string StartTime { get; set; }
            /// <summary>
            /// 服务器定时处理模型
            /// </summary>
            public TimerMode TimerMode { get; set; }
        }
        /// <summary>
        /// 服务处理方法
        /// </summary>
        public enum TimerMode
        {
            /// <summary>
            /// 轮询方式
            /// </summary>
            Interval = 0,
            /// <summary>
            /// 一个月中某个天数的指定时间
            /// </summary>
            Month = 1,
            /// <summary>
            /// 一周中的周几的指定时间
            /// </summary>
            Week = 2,
            /// <summary>
            /// 一天中的指定时间
            /// </summary>
            Day = 3,
            /// <summary>
            /// 一年中第几天的指定时间
            /// </summary>
            Year = 4,
            /// <summary>
            /// 一年中的指定日期的指定时间
            /// </summary>
            Date = 5,
            /// <summary>
            /// 未设置
            /// </summary>
            NoSet
        }
        /// <summary>
        /// 服务处理方法
        /// </summary>
        public enum ServiceStatus
        {
            /// <summary>
            /// 休眠中
            /// </summary>
            Sleep = 0,
            /// <summary>
            /// 服务在执行过程中
            /// </summary>
            Running = 1
        }
        #endregion
    
        #region 定时服务休眠时间计算类
        /// <summary>
        /// 定时服务休眠时间计算类
        /// </summary>
        public class TimerControl
        {
            #region 私有成员
            /// <summary>
            /// 间隔单位
            /// </summary>
            private TimerMode type;
            /// <summary>
            /// 月份
            /// </summary>
            private int Month;
            /// <summary>
            ////// </summary>
            private int Day;
            /// <summary>
            /// 小时
            /// </summary>
            private int Hour;
            /// <summary>
            /// 分钟
            /// </summary>
            private int Minute = 0;
            #endregion
    
            #region 公共成员方法
            /// <summary>
            /// StartTime值为:
            /// 
            /// TimerMode=TimerMode.Month    "09|04:30"    -表示每月9号的凌晨4点30分
            ///    TimerMode=TimerMode.Week     "0|04:30"    -表示每星期天的4点30分
            /// TimerMode=TimerMode.Week     "6|04:00"    -表示每星期6的4点30分
            ///    TimerMode=TimerMode.Day          "|04:00"    -表示每天的4点00分
            ///    TimerMode=TimerMode.Date "08-10|04:00"    -表示每年8月10号的4点00分执行一次
            ///    TimerMode=TimerMode.Year   "246|04"        -表示每年第246天的4点00分执行一次(可以不填写分钟默认为00)
            /// </summary>
            /// <param name="StartTime"></param>
            /// <param name="timeMode"></param>
            public TimerControl( string StartTime, TimerMode timeMode )
            {
                //Regex regEx = new Regex( @"(?<Type>[MWDY])(?<Days>/d+)?/|(?<Hour>/d+):?(?<Minute>[0-5]/d?)?", RegexOptions.Compiled | RegexOptions.IgnoreCase );
                Regex regEx = new Regex( @"^(?:(?<Month>[0]?/d|1[0-2])-)?(?<Days>/d{1,3})?/|(?<Hour>[01]?/d|2[0-3])(?::(?<Minute>[0-5]/d?))?$", RegexOptions.Compiled | RegexOptions.IgnoreCase );
    
                this.type = timeMode;
    
                Match m = regEx.Match( StartTime );
                if ( m.Success )
                {
                    if ( String.IsNullOrEmpty( m.Groups["Month"].Value ) && this.type == TimerMode.Date )
                        throw new Exception( "定时器时间配置异常!" );
    
                    if ( !String.IsNullOrEmpty( m.Groups["Month"].Value ) )
                        this.Month = Convert.ToInt32( m.Groups["Month"].Value );
    
                    if ( !String.IsNullOrEmpty( m.Groups["Days"].Value ) )
                        this.Day = Convert.ToInt32( m.Groups["Days"].Value );
    
                    this.Hour = Convert.ToInt32( m.Groups["Hour"].Value );
    
                    if ( !String.IsNullOrEmpty( m.Groups["Minute"].Value ) )
                        this.Minute = Convert.ToInt32( m.Groups["Minute"].Value );
                }
                else
                    throw new Exception( "定时器时间配置异常!" );
            }
            /// <summary>
            /// 判断时间是否到了
            /// </summary>
            /// <returns></returns>
            public bool TimeIsUp
            {
                get
                {
                    DateTime dt = DateTime.Now;
                    switch ( type )
                    {
                        case TimerMode.Day:
                            return ( dt.Hour == this.Hour && dt.Minute == this.Minute );
                        case TimerMode.Month:
                            return ( dt.Day == this.Day && dt.Hour == this.Hour && dt.Minute == this.Minute );
                        case TimerMode.Week:
                            return ( ( ( int )dt.DayOfWeek ) == this.Day && dt.Hour == this.Hour && dt.Minute == this.Minute );
                        case TimerMode.Date:
                            return ( dt.Month == this.Month && dt.Day == this.Day && dt.Hour == this.Hour && dt.Minute == this.Minute );
                        case TimerMode.Year:
                            return ( dt.DayOfYear == this.Day && dt.Hour == this.Hour && dt.Minute == this.Minute );
                    }
                    return false;
                }
            }
            /// <summary>
            /// 从现在起到下次时间到还有多少时间
            /// </summary>
            /// <returns></returns>
            public TimeSpan GetNextTimeUp()
            {
                ///目标时间
                DateTime _NextDateTime = this.GetNextDateTime();    // 保存下一次要执行的时间
                TimeSpan NextCrtFileTime = _NextDateTime - DateTime.Now;
    
                if ( ( int )NextCrtFileTime.TotalMilliseconds > int.MaxValue )    // 如果要休眠的时间间隔超过int类型可以表示的毫秒时,先休眠到int.MaxValue,然后再次休眠
                    NextCrtFileTime = new TimeSpan( int.MaxValue );
    
                return NextCrtFileTime;
            }
            /// <summary>
            /// 获取下一次指定配置的时间是多少
            /// </summary>
            /// <returns></returns>
            public DateTime GetNextDateTime()
            {
                DateTime dt = DateTime.Now;
                DateTime now, target;
                switch ( this.type )
                {
                    case TimerMode.Day:
                        #region 每天指定某时执行一次
                        now = new DateTime( 1, 1, 1, dt.Hour, dt.Minute, 0 );
                        target = new DateTime( 1, 1, 1, this.Hour, this.Minute, 0 );
                        if ( now.Ticks >= target.Ticks ) dt = dt.AddDays( 1.0 );    //如果当前时间小于指定时刻,则不需要加天
    
                        dt = new DateTime( dt.Year, dt.Month, dt.Day, this.Hour, this.Minute, 0 );
                        #endregion
                        break;
                    case TimerMode.Month:
                        #region 每月指定某天某时执行一次
                        now = new DateTime( 1, 1, dt.Day, dt.Hour, dt.Minute, 0 );
                        target = new DateTime( 1, 1, this.Day, this.Hour, this.Minute, 0 );
                        if ( now.Ticks >= target.Ticks ) dt = dt.AddMonths( 1 );
    
                        dt = new DateTime( dt.Year, dt.Month, this.Day, this.Hour, this.Minute, 0 );
                        #endregion
                        break;
                    case TimerMode.Week:
                        #region 每星期指定星期某时执行一次
                        int dow = ( int )dt.DayOfWeek;
                        now = new DateTime( 1, 1, dow + 1, dt.Hour, dt.Minute, 0 );
                        target = new DateTime( 1, 1, this.Day + 1, this.Hour, this.Minute, 0 );
    
                        if ( now.Ticks >= target.Ticks )
                            dt = dt.AddDays( this.Day - dow + 7 );
                        else
                            dt = dt.AddDays( this.Day - dow );
    
                        dt = new DateTime( dt.Year, dt.Month, dt.Day, this.Hour, this.Minute, 0 );
                        #endregion
                        break;
                    case TimerMode.Date:
                        #region 每年指定某月某日某时执行一次
                        now = new DateTime( 1, dt.Month, dt.Day, dt.Hour, dt.Minute, 0 );
                        target = new DateTime( 1, this.Month, this.Day, this.Hour, this.Minute, 0 );
                        if ( now.Ticks >= target.Ticks ) dt = dt.AddYears( 1 );
    
                        dt = new DateTime( dt.Year, this.Month, this.Day, this.Hour, this.Minute, 0 );
                        #endregion
                        break;
                    case TimerMode.Year:
                        #region 每年指定第N天某时执行一次
                        now = new DateTime( 1, 1, 1, dt.Hour, dt.Minute, 0 );
                        target = new DateTime( 1, 1, 1, this.Hour, this.Minute, 0 );
                        if ( dt.DayOfYear > this.Day || dt.DayOfYear == this.Day && now.Ticks >= target.Ticks ) dt = dt.AddYears( 1 );
                        dt = dt.AddDays( this.Day - dt.DayOfYear );
    
                        dt = new DateTime( dt.Year, dt.Month, dt.Day, this.Hour, this.Minute, 0 );
                        #endregion
                        break;
                    default:
                        throw new Exception( "定时器时间配置异常!" );
                }
    
                return dt;
            }
            #endregion
        }
        #endregion
    }
  • 相关阅读:
    [LeetCode] Permutation Sequence, Solution
    [LeetCode] Spiral Matrix II, Solution
    同学你好, google到你的帖子,想问下为什么你的解法不用考虑到2个数相同的情况?比如4,4,8...
    [LeetCode] Regular Expression Matching, Solution
    {4,4,8}倒还好,不过{4,8}就会有问题了。这里倒是一个bug。一个可用的办法就是用一个vis...
    [LeetCode] Merge Intervals, Solution
    请问这个解法的时间复杂度怎么分析?谢谢!
    未做题
    dude, visited[i 1] == 0 should be visited[i 1]...
    发布一个开源的c++网络事件库【转载Zark@cppthinker.com】
  • 原文地址:https://www.cnblogs.com/bohetang/p/4039531.html
Copyright © 2011-2022 走看看