7

This is next step of my previous question.


I'm creating a C# WinForm Application which will display Network Activity (Bytes Received / Bytes Sent) for a given Process (For Example: Process name 's chrome.exe) and Speed in Megabits/s generated by the Process.

While using the Performance Counters IO Read Bytes/sec and IO Read Bytes/sec shows I/O read and write bytes instead of 'Send and Received Bytes'.

PS: I/O counts all File, Network, and Device I/Os bytes generated by a Process. But, I wants only Network Bytes generated by a particular Process.

I wanted to retrieve only Bytes Received and Bytes Sent. But, don't know what counters are used to get these bytes of a Process.

I have searched these links for this purpose but not useful:

Here is Process's Performance Counter code that tried:

PerformanceCounter bytesReceived = new PerformanceCounter("Process", "IO Read Bytes/sec");
PerformanceCounter bytesSent = new PerformanceCounter("Process", "IO Write Bytes/sec");
string ProcessName = "chrome";
bytesReceived.InstanceName = ProcessName;
bytesSent.InstanceName = ProcessName;

Question: How I can only get the Received and Sent Bytes generated by a Process for a network activity.

5377037
  • 9,493
  • 12
  • 43
  • 73
  • https://stackoverflow.com/questions/17026204/retrieve-process-network-usage – Alex Sep 22 '19 at 23:37
  • https://social.msdn.microsoft.com/Forums/vstudio/en-US/b6b43fc4-053f-44e4-9956-65a97dbc2916/c-application-for-monitoring-network-traffic-per-process?forum=csharpgeneral – Alex Sep 22 '19 at 23:39
  • The solution I wants using `PerformanceCounter`. – 5377037 Sep 23 '19 at 10:21
  • After carefully reading the links you provided and [this one](https://social.msdn.microsoft.com/Forums/vstudio/en-US/e796ef0a-ab05-482d-85d8-03782b50e013/how-can-i-get-network-usage-per-process?forum=csharpgeneral), I am pretty sure that this is impossible with the `PerformanceCounter` class, since it only draws from a restricted set of more or less pre-defined counters. Listing the available counters on my local system showed no opportunities to target a certain process without including disk I/O. – janw Sep 23 '19 at 22:33
  • @JanWichelmann do you mean its not possible with `PerformanceCounter`? If yes, then how I can achieve it otherwise. – 5377037 Sep 24 '19 at 04:45
  • One of the [answers you cited](https://stackoverflow.com/a/45076244/8528014) looks pretty complete and usable to me. You just have to adjust it to use the appropriate process ID. I will post a complete answer later, if you like. – janw Sep 24 '19 at 06:41
  • Yes, I like to see the answer. – 5377037 Sep 24 '19 at 07:06

1 Answers1

5

As already mentioned in the comments, I don't believe there is a way to achieve this using the PerformanceCounter class. Since it uses Windows' built-in performance counters, this can be verified by querying the entire list of installed counters using the typeperf command. On my local machine this yields about 3.200 different counters, which I went through to verify my claim. There actually are counters for network send/receive (even for specific network interfaces/adapters or processors), but none of them can filter for a specific process or process family.


Thus, the easier way might be to use this (already quite complete) answer, which makes use of the Microsoft.Diagnostics.Tracing.TraceEvent NuGet package. For testing I condensed it down to a minimal amount of code and modified it to capture the traffic of an entire process family.

static void Main(string[] args)
{
    // Counter variables
    var counterLock = new object();
    int received = 0;
    int sent = 0;

    // Fetch ID of all Firefox processes
    var processList = Process.GetProcessesByName("firefox").Select(p => p.Id).ToHashSet();

    // Run in another thread, since this will be a blocking operation (see below)
    Task.Run(() =>
    {
        // Start ETW session
        using(var session = new TraceEventSession("MyKernelAndClrEventsSession"))
        {
            // Query network events
            session.EnableKernelProvider(KernelTraceEventParser.Keywords.NetworkTCPIP);

            // Subscribe to trace events
            // These will be called by another thread, so locking is needed here
            session.Source.Kernel.TcpIpRecv += data =>
            {
                if(processList.Contains(data.ProcessID))
                    lock(counterLock)
                        received += data.size;
            };
            session.Source.Kernel.TcpIpSend += data =>
            {
                if(processList.Contains(data.ProcessID))
                    lock(counterLock)
                        sent += data.size;
            };

            // Process all events (this will block)
            session.Source.Process();
        }
    });

    // Program logic to handle counter values
    while(true)
    {
        // Wait some time and print current counter status
        Task.Delay(2000).Wait();
        lock(counterLock)
            Console.WriteLine($"Sent: {sent.ToString("N0")} bytes    Received: {received.ToString("N0")} bytes");
    }
}

Note that you need elevated (administrator) privileges to execute this code.

I tested with Mozilla Firefox, which had 10 processes (7 tabs) running at that time; I downloaded a big file, and the program correctly printed the added network traffic (plus some noise from active tabs), without including the involved disk accesses (which would have at least doubled the measured traffic).

Also note that this only captures TCP/IP traffic; to also capture UDP/IP traffic, you need to subscribe to the UdpIpSend and UdpIpRecv events.

janw
  • 5,204
  • 5
  • 24
  • 43