Windows服务启动、停止、调试问题

3
我有一个服务,我不知道它的运行时间,大约是7秒钟左右。由于某种原因,在第一次运行后,该服务停止工作,我无法进行调试。在服务管理器上它一直显示"正在启动",而我在附加进程窗口中找不到它。
当我尝试停止它时,停止按钮只会出现一秒钟。即使我按下按钮,也会收到一个错误,指出"Windows 无法停止本地计算机上的 'Splive' 服务。该服务未返回错误信息。这可能是内部 Windows 错误或内部服务错误。"
如何处理这个问题才是最好的方法?
static void Main(string[] args)
    {
        ServiceBase.Run(new Program());
        ServiceController service = new ServiceController();
        service.ServiceName = "SpLive";
        service.Start();
        //Sp objSportingbet = new Sp();
        //objSportingbet.getListingsFromSp();
    }
    public Program()
    {
        this.ServiceName = "SpLive";
    }
    protected override void OnStart(string[] args)
    {
        base.OnStart(args);
        objSportingbet.getListingsFromSp();
        timer1.Elapsed += new ElapsedEventHandler(timer1_Elapsed);
        timer1.Interval = 7000;
        timer1.Enabled = true;
        timer1.Start();
    }
    protected override void OnStop()
    {
        base.OnStop();
        timer1.Elapsed += new ElapsedEventHandler(timer1_Elapsed);
        timer1.Interval = 7000;
        timer1.Enabled = false;
        timer1.Start();
    }
    private void timer1_Elapsed(object sender, EventArgs e)
    {
        ServiceController service = new ServiceController();
        service.ServiceName = "Sp";
        if (service.Status == ServiceControllerStatus.Stopped)
        {
            service.Start();
        }
        if (service.Status == ServiceControllerStatus.Running)
        {
            service.Stop();
        }
        timer1.Stop();
    }

    private void InitializeComponent()
    {
        // 
        // Program
        // 
        this.CanPauseAndContinue = true;
        this.CanShutdown = true;

    }

使用异常处理并记录异常...这将有助于您找到问题。 - Damith
取决于情况,但你有检查事件日志吗? - Random Dev
我应该在OnStart()和OnStop()中添加异常。我没有从GetListingsFromSp()中得到任何异常。 - Hadi Tok
这段代码是在你的服务内部还是测试程序中?因为 service.Stop() 应该停止你的服务,如果这段代码在你的服务中,那么这看起来对我来说有些奇怪(请参阅:http://msdn.microsoft.com/en-us/library/system.serviceprocess.servicecontroller.stop.aspx)。 - Random Dev
3个回答

5

配置服务在调试器下启动:http://support.microsoft.com/kb/824344,注意其中的"将服务配置为与WinDbg调试器一起启动"部分。

补充(现在问题中有代码):

static void Main(string[] args)
{
   ServiceBase.Run(new Program());
   ServiceController service = new ServiceController();
   service.ServiceName = "SpLive";
   service.Start();

ServiceBase.Run(instance)不会返回,直到服务被关闭,因此您正在运行服务,然后在其关闭后要求SCM运行服务...这只会导致混乱。

除此之外,还有一个计时器来尝试反转服务的状态(已启动<->已停止),这让我想到您需要考虑Windows服务的基本进程模型:

当exe只实现了一个服务时:

  1. 服务已启动(在系统启动时,从用户请求中...):SCM运行注册的命令行

  2. Main运行,告诉SCM(通过ServiceBase.Run)这是哪个服务。这必须与步骤1中使用的注册匹配。

  3. 传递给ServiceBase.Run的实例调用其OnStart。服务应该开始它将执行的活动,然后返回(即异步操作、新线程和线程池是可以的;继续在调用OnStart的线程上进行不可以)。

  4. 当收到关闭信号(来自任何来源)时,调用OnStop。这应该触发停止所有OnStart启动的活动(或者自启动以来启动的活动),并等待它们停止,然后返回。

服务停止自身的唯一原因是如果其他东西(例如其自己的管理API)触发它,但最好从UI使用SCM。


我按照页面上的指示操作了,现在出现了Windbg屏幕,但我无法理解任何输出内容。我无法复制或获取屏幕截图,除了“找不到符号文件”之外,没有重要信息。 - Hadi Tok
@Haditok 在使用WinDBG进行.NET调试时需要使用SOS扩展,并解决符号文件的访问问题(最简单的方法是将它们与exe/dll文件放在一起)。关于使用WinDBG的大量在线帮助以及一些好书籍可供参考。 - Richard

4
理想情况下,您希望调试服务的 OnStart 方法以查看发生了什么。这是可能的:
protected override void OnStart(string[] args)
{
    #if DEBUG
    Debugger.Launch();
    #endif
    ...
}

即使服务未被标记为桌面交互式,此方法仍然可行。


1

OnStart和OnStop处理程序有固定的时间限制。对于停止操作如何工作(是否等待线程完成),我不清楚。但是对于OnStart,在您的情况下(我知道它是一个旧线程..),我建议将所有应用程序代码移动到计时器回调中,并在OnStart函数中设置计时器。我将我的设置为约1分钟。 OnStart将立即退出,这满足了服务管理器的要求。但现在,您有一个线程将在大约一分钟后启动,这使您有时间将进程附加到调试器。显然,在OnStart计时器回调中的第一条指令上设置断点。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接