转自http://blog.csdn.net/linux7985/article/details/5843394
写服务时,都需要为定时器写不少的代码,感觉很麻烦,今天把这些代码封装一下,希望能简化一下这方面的工作,把精力都集中在功能上
本定时器组件,每次只启动一个服务实例进行处理,而不会同时多次执行服务代码。
下面是应用实例
从组件类派生一个子类,可以看到,需要写的代码很少
[c-sharp] view plaincopy
- 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();
以下是组件的源代码
[c-sharp] view plaincopy
- 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
- }
时间: 2024-10-15 05:05:25