You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将抓包存日志脚本转为Windows服务启动失败问题排查

相关代码与报错信息

启动失败的Windows服务代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using CapturingAndParsingPackets;
using PacketDotNet;
using SharpPcap;

namespace CaptureService
{
    public partial class Service1 : ServiceBase
    {
        private static bool _stopCapturing;
        string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);//获取桌面路径
        string filename = DateTime.Now.ToString("yyyy-MM-dd--HH-mm-ss");//用日期命名文件

        public Service1()
        {
            InitializeComponent();
            var devices = CaptureDeviceList.Instance; //获取本地设备
            if (devices.Count < 1)
            {
                OnStop();
                return;
            }
        }

        protected override void OnStart(string[] args)
        {
            var devices = CaptureDeviceList.Instance; //获取本地设备
            //设置输出类型
            var defaultOutputType = StringOutputType.Normal;
            var outputTypeValues = Enum.GetValues(typeof(StringOutputType));
            StringOutputType selectedOutputType = defaultOutputType;
            int userSelectedOutputType;
            userSelectedOutputType = 3;
            selectedOutputType = (StringOutputType)userSelectedOutputType;
            //读取本地设备
            var device = devices[3];
            //读取数据包
            var readTimeoutMilliseconds = 1000;
            device.Open(DeviceModes.Promiscuous, readTimeoutMilliseconds);
            //设置过滤规则
            string filter = "host 192.168.0.212";
            device.Filter = filter;

            
            PacketCapture e;
            var status = device.GetNextPacket(out e);

            var rawCapture = e.GetPacket();

            // 使用PacketDotNet解析数据包并输出高级信息
            var p = Packet.ParsePacket(rawCapture.GetLinkLayers(), rawCapture.Data);

            // 在桌面创建日志文件并写入日志
            using (StreamWriter w = File.AppendText(path + "\\" + filename + ".log"))
            {
                Log(p.ToString(selectedOutputType) + p.PrintHex(), w);
            }
            
            device.Close();
        }

        public static void Log(string logMessage, TextWriter txtWriter)
        {
            try
            {
                txtWriter.Write("\r\n日志条目 : ");
                txtWriter.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(),
                    DateTime.Now.ToLongDateString());
                txtWriter.WriteLine();
                txtWriter.WriteLine(logMessage);
                txtWriter.WriteLine("============================================================================================================");
            }
            catch (Exception)
            {
            }
        }
        protected override void OnStop()
        {
            using (StreamWriter w = File.AppendText(path + "\\" + filename + ".log"))
            {
                Log("服务于 " + DateTime.Now + " 停止", w);
            }
        }
    }
}

可正常运行的VS控制台抓包脚本

using System;
using PacketDotNet;
using SharpPcap;
using System.IO;
using System.Reflection;
using log4net;
using log4net.Config;

namespace CapturingAndParsingPackets
{
    class MainClass
    {
        // 用于停止捕获循环的标志
        private static bool _stopCapturing;

        public static void Main(string[] args)
        {
            // 打印SharpPcap版本
            var ver = SharpPcap.Pcap.SharpPcapVersion;
            Console.WriteLine("使用SharpPcap {0}的PacketDotNet示例", ver);

            // 获取设备列表
            var devices = CaptureDeviceList.Instance;

            // 如果没有找到设备,打印错误信息
            if (devices.Count < 1)
            {
                Console.WriteLine("本机未找到任何设备");
                return;
            }

            Console.WriteLine();
            Console.WriteLine("本机可用设备如下:");
            Console.WriteLine("----------------------------------------------------");
            Console.WriteLine();

            var i = 0;

            // 打印设备信息
            foreach (var dev in devices)
            {
                /* 描述信息 */
                Console.WriteLine("{0}) {1} {2}", i, dev.Name, dev.Description);
                i++;
            }

            Console.WriteLine();
            Console.Write("-- 请选择要捕获的设备: ");


            Console.WriteLine();
            Console.WriteLine("输出详细程度选项");
            Console.WriteLine("----------------------------------------------------");
            Console.WriteLine();
            var defaultOutputType = StringOutputType.Normal;
            var outputTypeValues = Enum.GetValues(typeof(StringOutputType));
            foreach (StringOutputType outputType in outputTypeValues)
            {
                Console.Write("{0} - {1}", (int)outputType, outputType);
                if (outputType == defaultOutputType)
                {
                    Console.Write(" (默认)");
                }

                Console.WriteLine("");
            }

            Console.WriteLine();
            Console.Write("-- 请选择详细程度(或按回车键使用默认值): ");
            StringOutputType selectedOutputType = defaultOutputType;
            int userSelectedOutputType;
            // 固定选择
            userSelectedOutputType = 3;
            selectedOutputType = (StringOutputType)userSelectedOutputType;


            // 注册取消处理程序,用于中断捕获循环
            Console.CancelKeyPress += HandleCancelKeyPress;

            // 固定选择设备
            var device = devices[3];

            // 打开设备进行捕获
            var readTimeoutMilliseconds = 1000;
            device.Open(DeviceModes.Promiscuous, readTimeoutMilliseconds);
            // 过滤规则:捕获目标主机192.168.0.212的流量
            // 也可以设置为"filter = 'ip';"作为默认规则
            string filter = "host 192.168.0.212";
            device.Filter = filter;


            Console.WriteLine();
            Console.WriteLine("-- 正在监听 {0}, 按'ctrl-c'停止...",
                              device.Name);

            while (_stopCapturing == false)
            {
                PacketCapture e;
                var status = device.GetNextPacket(out e);

                // 如果GetNextRawPacket()超时,可能返回null数据包,此时应回到循环开头尝试获取下一个数据包
                if (status != GetPacketStatus.PacketRead)
                {
                    // 返回循环开头
                    continue;
                }

                var rawCapture = e.GetPacket();

                // 使用PacketDotNet解析数据包并输出高级信息
                var p = Packet.ParsePacket(rawCapture.GetLinkLayers(), rawCapture.Data);



                Console.WriteLine(p.ToString(selectedOutputType) + p.PrintHex());
                Console.WriteLine("============================================================================================================");
                using (StreamWriter w = File.AppendText("networkTraffic.log"))
                {
                    Log(p.ToString(selectedOutputType), w);
                    Log(p.PrintHex(), w);
                }
            }

            Console.WriteLine("-- 捕获已停止");

            // 打印设备统计信息
            Console.WriteLine(device.Statistics.ToString());


            // 关闭pcap设备
            device.Close();
        }

        static void Log(string logMessage, TextWriter txtWriter)
        {
            try
            {
                txtWriter.Write("\r\n日志条目 : ");
                txtWriter.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(),
                    DateTime.Now.ToLongDateString());
                txtWriter.WriteLine();
                txtWriter.WriteLine(logMessage);
                txtWriter.WriteLine("============================================================================================================");
            }
            catch (Exception)
            {
            }
        }



        static void HandleCancelKeyPress(object sender, ConsoleCancelEventArgs e)
        {
            Console.WriteLine("-- 正在停止捕获");
            _stopCapturing = true;

            // 告知处理程序我们将自行处理关闭,返回后不要终止进程,因为我们需要做一些收尾工作(比如关闭打开的捕获设备)
            e.Cancel = true;
        }
    }
}

事件查看器报错信息

错误1064

Application: CaptureTrafficService.exe
Framework Version: v4.0.30319
Description: 进程因未处理的异常而终止。
Exception Info: System.IO.FileNotFoundException
   at CaptureTrafficService.Service1.OnStart(System.String[])
   at System.ServiceProcess.ServiceBase.ServiceQueuedMainCallback(System.Object)
   at System.ServiceProcess.ServiceBase.Run(System.ServiceProcess.ServiceBase[])
   at CaptureTrafficService.Program.Main()
无法启动服务。System.IO.FileNotFoundException: 未能加载文件或程序集“netstandard, Version=2.1.0.0, Culture=neutral, PublicKeyToken=cc7b1xxxxxxxxxxx”或它的某一个依赖项。系统找不到指定的文件。
文件名: "netstandard, Version=2.1.0.0, Culture=neutral, PublicKeyToken=cc7b1xxxxxxxxxxx"
   at CaptureTrafficService.Service1.OnStart(String[] args)
   at System.ServiceProcess.ServiceBase.ServiceQueuedMainCallback(Object state)

错误1053(移除while循环后)

Application: CaptureTrafficService.exe
Framework Version: v4.0.30319
Description: 进程因未处理的异常而终止。
Exception Info: System.IO.FileNotFoundException

Exception Info: System.IO.FileNotFoundException
   at CaptureService.Service1..ctor()
   at CaptureService.Program.Main()

解决方案

1. 解决netstandard程序集加载失败问题

(1)确认项目目标框架兼容性

如果Windows服务项目基于.NET Framework,需将目标框架升级至4.8及以上(.NET Framework 4.8完全支持.NET Standard 2.1),低版本框架无法兼容该程序集。

(2)配置程序集绑定重定向

在项目的app.config文件中添加以下配置,解决版本不匹配导致的加载失败:

<runtime>
  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    <dependentAssembly>
      <assemblyIdentity name="netstandard" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
      <bindingRedirect oldVersion="0.0.0.0-2.1.0.0" newVersion="2.1.0.0" />
    </dependentAssembly>
  </assemblyBinding>
</runtime>

(3)调整NuGet包版本

若使用的SharpPcap、PacketDotNet版本过高,可降级到支持.NET Framework的稳定版本,例如:

  • SharpPcap: 4.2.0
  • PacketDotNet: 1.4.0

2. 修复Windows服务启动超时(错误1053)

Windows服务的OnStart方法必须在30秒内返回,不能包含阻塞逻辑。需将抓包逻辑移至后台线程执行,修改后的核心代码示例:

using System;
using System.ServiceProcess;
using System.IO;
using PacketDotNet;
using SharpPcap;
using System.Threading;

namespace CaptureService
{
    public partial class Service1 : ServiceBase
    {
        private bool _stopCapturing;
        private Thread _captureThread;
        private ICaptureDevice _captureDevice;
        private readonly string _logPath;
        private readonly string _logFileName;

        public Service1()
        {
            InitializeComponent();
            _logPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData); // 使用公共目录避免权限问题
            _logFileName = DateTime.Now.ToString("yyyy-MM-dd--HH-mm-ss") + ".log";
        }

        protected override void OnStart(string[] args)
        {
            // 后台线程执行抓包逻辑,避免阻塞OnStart
            _captureThread = new Thread(StartCapturing)
            {
                IsBackground = true
            };
            _captureThread.Start();
        }

        private void StartCapturing()
        {
            try
            {
                var devices = CaptureDeviceList.Instance;
                if (devices.Count < 1)
                {
                    LogMessage("未找到任何网络设备");
                    OnStop();
                    return;
                }

                var device = devices[3];
                var readTimeoutMilliseconds = 1000;
                device.Open(DeviceModes.Promiscuous, readTimeoutMilliseconds);
                device.Filter = "host 192.168.0.212";
                _captureDevice = device;

                var selectedOutputType = (StringOutputType)3;

                LogMessage("服务已启动,开始捕获流量");

                while (!_stopCapturing)
                {
                    PacketCapture packetCapture;
                    var status = device.GetNextPacket(out packetCapture);

                    if (status != GetPacketStatus.PacketRead)
                    {
                        Thread.Sleep(100);
                        continue;
                    }

                    var rawCapture = packetCapture.GetPacket();
                    var packet = Packet.ParsePacket(rawCapture.GetLinkLayers(), rawCapture.Data);

                    LogMessage(packet.ToString(selectedOutputType) + packet.PrintHex());
                }
            }
            catch (Exception ex)
            {
                LogMessage("捕获过程中发生错误: " + ex.ToString());
            }
            finally
            {
                _captureDevice?.Close();
                LogMessage("抓包设备已关闭");
            }
        }

        protected override void OnStop()
        {
            _stopCapturing = true;
            _captureThread?.Join(5000); // 等待线程退出,最多5秒
            LogMessage("服务已停止");
        }

        private void LogMessage(string message)
        {
            try
            {
                using (var writer = File.AppendText(Path.Combine(_logPath, _logFileName)))
                {
                    writer.Write("\r\n日志条目 : ");
                    writer.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(), DateTime.Now.ToLongDateString());
                    writer.WriteLine(message);
                    writer.WriteLine("============================================================================================================");
                }
            }
            catch { }
        }
    }
}

3. 额外注意事项

  • 服务权限:运行服务的账户需具备访问网络设备和写入日志目录的权限,建议使用Local System账户。
  • 日志路径:避免使用当前用户桌面路径(服务账户可能无法访问),优先选择公共应用数据目录。

内容的提问来源于stack exchange,提问作者Sam1916

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 21:10:24