检索进程的网络使用情况

27

如何让进程发送/接收字节?最好的方法是使用C#。

我搜索了很多,没有找到简单的解决方案。有些解决方案建议在计算机上安装WinPCap并使用该库进行工作。

就像这个人问的:需要在托管代码中具有“带网络活动的进程”功能 - 就像resmon.exe那样 我不想要这个库的开销。

有没有简单的解决方案? 实际上,我想要 Windows 的资源监视器在“具有网络活动的进程”选项卡下提供的精确数据:“输入图像说明”

Windows 资源监视器如何获取此信息? 有什么例子吗?

此外,尝试使用此处提到的计数器方法:缺少网络发送/接收,但没有成功 - 因为并非每个进程都显示在此计数器下。 再次想知道资源监视器即使不使用此计数器也如何获得此信息...


1
你在性能计数器中没有找到答案吗? http://www.codeproject.com/Articles/8590/An-Introduction-To-Performance-Counters - Yogee
我尝试使用性能计数器的方法,但没有成功 - 即使阅读了您添加的链接。 - Tomer Peled
1
https://dev59.com/P3RC5IYBdhLWcg3wAcXU - Marcello Romani
已经阅读了 - 我不想使用任何第三方解决方案。没有其他本地方式吗? - Tomer Peled
3个回答

19

资源监视器使用ETW——值得庆幸的是,Microsoft创建了一个漂亮的nuget .net封装包,使其更易于使用。

我最近编写了类似以下内容来报告我的进程的网络IO:

using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.Diagnostics.Tracing.Parsers;
using Microsoft.Diagnostics.Tracing.Session;

namespace ProcessMonitoring
{
    public sealed class NetworkPerformanceReporter : IDisposable
    {
        private DateTime m_EtwStartTime;
        private TraceEventSession m_EtwSession;

        private readonly Counters m_Counters = new Counters();

        private class Counters
        {
            public long Received;
            public long Sent;
        }

        private NetworkPerformanceReporter() { }

        public static NetworkPerformanceReporter Create()
        {
            var networkPerformancePresenter = new NetworkPerformanceReporter();
            networkPerformancePresenter.Initialise();
            return networkPerformancePresenter;
        }

        private void Initialise()
        {
            // Note that the ETW class blocks processing messages, so should be run on a different thread if you want the application to remain responsive.
            Task.Run(() => StartEtwSession()); 
        }

        private void StartEtwSession()
        {
            try
            {
                var processId = Process.GetCurrentProcess().Id;
                ResetCounters();

                using (m_EtwSession = new TraceEventSession("MyKernelAndClrEventsSession"))
                {
                    m_EtwSession.EnableKernelProvider(KernelTraceEventParser.Keywords.NetworkTCPIP);

                    m_EtwSession.Source.Kernel.TcpIpRecv += data =>
                    {
                        if (data.ProcessID == processId)
                        {
                            lock (m_Counters)
                            {
                                m_Counters.Received += data.size;
                            }
                        }
                    };

                    m_EtwSession.Source.Kernel.TcpIpSend += data =>
                    {
                        if (data.ProcessID == processId)
                        {
                            lock (m_Counters)
                            {
                                m_Counters.Sent += data.size;
                            }
                        }
                    };

                    m_EtwSession.Source.Process();
                }
            }
            catch
            {
                ResetCounters(); // Stop reporting figures
                // Probably should log the exception
            }
        }

        public NetworkPerformanceData GetNetworkPerformanceData()
        {
            var timeDifferenceInSeconds = (DateTime.Now - m_EtwStartTime).TotalSeconds;

            NetworkPerformanceData networkData;

            lock (m_Counters)
            {
                networkData = new NetworkPerformanceData
                {
                    BytesReceived = Convert.ToInt64(m_Counters.Received / timeDifferenceInSeconds),
                    BytesSent = Convert.ToInt64(m_Counters.Sent / timeDifferenceInSeconds)
                };

            }

            // Reset the counters to get a fresh reading for next time this is called.
            ResetCounters();

            return networkData;
        }

        private void ResetCounters()
        {
            lock (m_Counters)
            {
                m_Counters.Sent = 0;
                m_Counters.Received = 0;
            }
            m_EtwStartTime = DateTime.Now;
        }

        public void Dispose()
        {
            m_EtwSession?.Dispose();
        }
    }

    public sealed class NetworkPerformanceData
    {
        public long BytesReceived { get; set; }
        public long BytesSent { get; set; }
    }
}

它必须在管理员权限下执行吗?我从EnableKernelProvider方法中得到了System.UnauthorizedAccessException异常。 - David Ferenczy Rogožan
1
我们是否可以在不使用管理员权限的情况下获取结果?仅列出当前用户进程的详细信息将起作用。 - Aniket Bhansali

2
你可以使用 PerformanceCounter。示例代码:
//Define 
string pn = "MyProcessName.exe";
var readOpSec  = new PerformanceCounter("Process","IO Read Operations/sec", pn);
var writeOpSec = new PerformanceCounter("Process","IO Write Operations/sec", pn);
var dataOpSec  = new PerformanceCounter("Process","IO Data Operations/sec", pn);
var readBytesSec = new PerformanceCounter("Process","IO Read Bytes/sec", pn);
var writeByteSec = new PerformanceCounter("Process","IO Write Bytes/sec", pn);
var dataBytesSec = new PerformanceCounter("Process","IO Data Bytes/sec", pn);

var counters = new List<PerformanceCounter>
                {
                readOpSec,
                writeOpSec,
                dataOpSec,
                readBytesSec,
                writeByteSec,
                dataBytesSec
                };

// get current value
foreach (PerformanceCounter counter in counters)
{
    float rawValue = counter.NextValue();

    // display the value
}

这是获取网络适配器性能计数器的方法。请注意,它不是针对特定进程的。

string cn = "get connection string from WMI";

var networkBytesSent = new PerformanceCounter("Network Interface", "Bytes Sent/sec", cn);
var networkBytesReceived = new PerformanceCounter("Network Interface", "Bytes Received/sec", cn);
var networkBytesTotal = new PerformanceCounter("Network Interface", "Bytes Total/sec", cn);

Counters.Add(networkBytesSent);
Counters.Add(networkBytesReceived);
Counters.Add(networkBytesTotal);

但我只想要网络活动,而不包括设备的I/O操作。 "IO读取操作/秒 - 显示进程发出读取I/O操作的速率(每秒事务数)。它计算进程生成的所有I/O活动,包括文件、网络和设备I/O。" - Tomer Peled
1
除非您使用第三方库,否则没有其他本地方式可以执行与单个进程相关的纯网络卡IO。我所做的是监视进程IO以及网络卡IO。后者并不特定于一个进程 - 即它收集所有IO计数器而不考虑进程。我将编辑代码以显示网络卡计数器。 - oleksii
1
谢谢你的解决方案,但那是我已经找到的解决方案之一,而且它不能满足我的目标——即仅获取进程网络使用情况。我正在寻找其他方法,就像 Windows 的资源监视器获得这些信息一样... - Tomer Peled
你不能只是比较进程使用率和系统使用率吗?假设你可以获取接口信息来确定最大带宽是多少(10/100等)。至少我认为这可能是我处理它的方式。 - TheXenocide
我曾提过类似的问题(几乎一样——stackoverflow误认为是同一个问题而错误地禁止了我,但我仍然不知道为什么结果为零,并且在互联网上没有找到任何线索)http://stackoverflow.com/questions/35460656/c-sharp-check-connectivity-to-endpoint?noredirect=1#comment58645231_35460656 但我还有一个未解决的问题,即我得到的结果始终为零。你是否遇到与我相同的结果为零的问题?需要一些指导来解决这个问题(我也更改了app.config以进行安全声明,如帖子中的链接...但还没有解决方案)。 - Eitan
注意,“从WMI获取连接字符串”可能会给您一个与PerformanceCounter用于抓取数据的不同网络接口名称(或“描述”)。在我的机器上,从NetworkInterface.GetAllNetworkInterfaces()获取的WiFi NIC接口名称是“Intel(R) Centrino(R) Ultimate-N...”,而从PerformanceCounterCategory("Network Interface").GetInstanceNames()获取的WiFi NIC接口名称是“Intel[R] Centrino[R] Ultimate-N...”,奇怪的是一个使用括号,另一个使用方括号... :/ - dean.huczok

0

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