【问题标题】:Runtime debugging tips for Windows Service?Windows 服务的运行时调试提示?
【发布时间】:2011-05-11 17:00:06
【问题描述】:

我有一个 Windows 服务,它监视连接到供应商硬件的 COM 端口。这是一个非常繁忙的硬件,它不断地轮询线路上的其他设备(这是一个双绞线 RS485“网络”)。我的软件需要在这条线上模拟 X 数量的硬件设备,所以我使用多层状态机进行多线程处理,以随时跟踪通信协议的位置。

问题在于 Windows 服务(这是我的第一个服务,顺便说一句),您需要进行一些调试以告知您是否正常工作。当我第一次开发这个状态机/多线程代码时,我有一个带有 RichTextBox 的 windows 窗体,它显示 ASCII 字符在行上来回显示。似乎我真的无法通过服务获得那种 GUI 的好处。我尝试通过另一个程序在服务中打开一个表单,该程序发送通过 OnCustomCommand() 处理程序接收的服务消息,但它似乎不起作用。我检查了“允许服务与桌面交互”和所有内容。我正在使用调试表单的 Show() 和 Hide() 方法。

我想我不需要看到所有单独的角色上线,但是那肯定会很好(我想我真的需要看到他们:-))。那么有没有人有任何疯狂的想法可以帮助我?我不想让一些 IPC 使系统陷入困境,这些 IPC 并不意味着肯定会通过的大量数据。不过,这只是非常短期的调试,只需确认程序、RS485 转 USB 加密狗和硬件都正常工作。

【问题讨论】:

    标签: winforms debugging windows-services


    【解决方案1】:

    使用OutputDebugString 写入调试缓冲区,然后使用DebugView 观看。如果您在 Windows XP 或更早版本上运行,则可以使用 PortMon 查看通过串行端口的原始字节。与日志文件相比的优点是开销很小,尤其是在您不看它的时候。您甚至可以从另一台机器上运行 DebugView 并远程监控您的服务。

    【讨论】:

    • 我一定是做错了什么,因为它不起作用。如果我理解正确,我应该能够将 Debug.WriteLine() 语句转储到任何地方并运行该程序,但我什么也没得到。
    • 我想我现在有了,但我必须使用 Debug.WriteLine()。
    【解决方案2】:

    我不知道它是否适合你,但我总是使用额外的 Main 构建我的服务,将它们构建为控制台应用程序以获取调试输出。

    编辑:

    一些例子:

    class Worker : ServiceBase
    {
    
    #if(RELEASE)
            /// <summary>
            /// The Main Thread where the Service is Run.
            /// </summary>
            static void Main()
            {
                ServiceBase.Run(new Worker());
            }
    #endif
    
    #if(DEBUG)
            public static void Main(String[] args)
            {
                Worker worker = new Worker();
                worker.OnStart(null);
                Console.ReadLine();
                worker.OnStop();
            }
    #endif
    
            // Other Service code
    }
    

    【讨论】:

      【解决方案3】:

      您可以将输出写入日志文件,然后使用另一个应用程序查看该文件。这个关于"tail" 的问题概述了使用windows 观看日志文件的几个选项。

      【讨论】:

        【解决方案4】:

        我在处理 Windows 服务时通常做的是创建它,以便它可以作为服务运行,也可以作为普通的旧命令行应用程序运行。您可以通过检查 Environment.UserInteractive 轻松检查您是否作为服务运行。如果此属性为 true,则您正在从命令行运行。如果该属性为 false,那么您正在作为服务运行。将此代码添加到 Program.cs,并在通常调用 ServiceBase.Run(servicesToRun) 的地方使用它

        /// <summary>Runs the provided service classes.</summary>
        /// <param name="servicesToRun">The service classes to run.</param>
        /// <param name="args">The command-line arguments to pass to the service classes.</param>
        private static void RunServices(IEnumerable<ServiceBase> servicesToRun, IEnumerable args)
        {
            var serviceBaseType = typeof(ServiceBase);
            var onStartMethod = serviceBaseType.GetMethod("OnStart", BindingFlags.Instance | BindingFlags.NonPublic);
            foreach (var service in servicesToRun)
            {
                onStartMethod.Invoke(service, new object[] { args });
                Console.WriteLine(service.ServiceName + " started.");
            }
        
            Console.WriteLine("Press any key to exit.");
            Console.ReadKey();
        
            var onStopMethod = serviceBaseType.GetMethod("OnStop", BindingFlags.Instance | BindingFlags.NonPublic);
            foreach (var service in servicesToRun)
            {
                onStopMethod.Invoke(service, null);
                Console.WriteLine(service.ServiceName + " stopped.");
            }
        }
        

        现在您可以调试您的服务、设置断点以及任何您想要的。当您运行您的应用程序时,您将获得一个控制台窗口,该窗口适合显示控制台消息,并且在您按下某个键之前它将保持打开状态。

        【讨论】:

          【解决方案5】:

          我在这里回答我自己的问题。我在这里尝试了一些建议,但这就是我最终要做的......

          我创建了一个带有单个 Button 和 RichTextBox 的 Windows 窗体应用程序。该应用程序在其末端构造了一个 NamedPipeServerStream。 Button 的工作是将“debug on”(命令 128)或“debug off”(129)发送到 Windows 服务。初始值为“调试关闭”。单击该按钮时,会向 Windows 服务发送 128 命令以打开调试。在 Windows 服务中,这触发了一个内部变量为真,加上它使用 NamedPipeClientStream 连接到 Form 应用程序,并在 COM 端口上接收或发送字符时开始使用 BinaryWriter 发送字符。在 Form 端,为管道上的 WaitForConnection() 创建了一个 BackgroundWorker。当它建立连接时,使用 BinaryReader.ReadString() 从管道中读取数据并将其发送到 RichTextBox。

          我快到了。当我再次单击调试按钮并且随后的单击未正确重做管道时,我正在破坏我的管道。总而言之,我对此很满意。如果有人感兴趣,我可以发布任何代码。感谢您的回复!

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-02-07
            相关资源
            最近更新 更多