简体   繁体   English

如何在Windows下监控进程网络使用情况

[英]How to monitor process network usage under windows

I am looking for a way to get the list of information as the Resource Monitor under windows did, such as: 我正在寻找一种方法来获取信息列表作为Windows下的资源监视器,如: 在此输入图像描述 I want to know the address and the among of send and receive usage of an selected application. 我想知道所选应用程序的地址发送接收使用情况。

At the beginning I am looking for a c++ win32 api or other open source library to do this, I can find something like GetProcessInformation but it does not include network information. 一开始我正在寻找一个c ++ win32 api或其他开源库来做到这一点,我可以找到像GetProcessInformation这样的东西,但它不包括网络信息。

I saw some similar topics but they didn't help. 我看到了一些类似的话题,但他们没有帮助。
Ref_001 , It seems the network monitor api cannot do application specific monitor. Ref_001 ,似乎网络监视器api无法做专用的监视器。
Ref_002 , I am not sure if OpenTrace/ProcessTrace/StopTrace can get me the network usage or not and also I am not sure how to use it. Ref_002 ,我不确定OpenTrace/ProcessTrace/StopTrace可以让我获得网络使用,而且我也不确定如何使用它。
Ref_003 , They are suggesting some tools but it is not what I want. Ref_003 ,他们建议使用一些工具,但这不是我想要的。

Windows supplies you with this information in two parts from different functions that you'll need to put together to get the full story. Windows通过两个部分为您提供这些信息,这些部分来自不同的功能,您需要将它们组合在一起以获得完整的故事。 Well, technically, it's three functions: for the second part of the data, there are separate functions for IPv4 and IPv6 data. 从技术上讲,它有三个功能:对于数据的第二部分,IPv4和IPv6数据有单独的功能。

The first function is GetExtendedTcpTable . 第一个函数是GetExtendedTcpTable To get all the information above, you'll probably need to call this (at least) twice: once with the TCP_TABLE_OWNER_PID_CONNECTIONS flag, and once with the TCP_TABLE_OWNER_MODULE_CONNECTIONS flag to retrieve both the PID and the module name of the local executable. 要获取上述所有信息,您可能需要调用此(至少)两次:一次使用TCP_TABLE_OWNER_PID_CONNECTIONS标志,一次使用TCP_TABLE_OWNER_MODULE_CONNECTIONS标志来检索PID和本地可执行文件的模块名称。

The second pair gets you statistics about the data sent/received on a particular connection. 第二对可以获取有关特定连接上发送/接收的数据的统计信息。 Each connection is identified by a combination of local address/port and remote address port (same as used above). 每个连接由本地地址/端口和远程地址端口的组合标识(与上面使用的相同)。 You retrieve the information with GetPerTcpConnectionEStats for IPv4 or GetPerTcp6ConnectionEStats for IPv6. 使用GetPerTcpConnectionEStats for IPv4或GetPerTcp6ConnectionEStats for IPv6检索信息。

Either of these will retrieve a table, with each row in the table containing statistics for one connection. 其中任何一个都将检索一个表,表中的每一行都包含一个连接的统计信息。 If you have (for example) multiple tabs open in your browser, could choose to show the data for each connection individually, or you could amalgamate them as you saw fit. 如果您(例如)在浏览器中打开了多个选项卡,则可以选择单独显示每个连接的数据,也可以按照您认为合适的方式将它们合并。

Thanks for your guidance Jerry Coffin 感谢您的指导Jerry Coffin

This is some very "POC" code I got working from these libraries. 这是我从这些库中获得的一些非常“POC”的代码。 Spoiler alert - Just implemented TCPv4 here. Spoiler alert - 刚刚在这里实现了TCPv4。 Code referenced from 代码引自

https://docs.microsoft.com/en-gb/windows/desktop/api/iphlpapi/nf-iphlpapi-getpertcpconnectionestats https://docs.microsoft.com/en-gb/windows/desktop/api/iphlpapi/nf-iphlpapi-getpertcpconnectionestats

Please forgive hacky nature of code, but I thought better to post than wait for that perfect day that will never arrive! 请原谅hacky代码的性质,但我认为发布比等待那个永远不会到来的完美日子更好!

Results container "NetworkPerformanceItem.h" 容器“NetworkPerformanceItem.h”的结果容器

#pragma once
#include "stdafx.h"
#include <string>
#include <windows.h>

class NetworkPerformanceItem
{
public:
    NetworkPerformanceItem();
    ~NetworkPerformanceItem();

    INT ProcessId;
    INT State;
    std::string LocalAddress;
    std::string RemoteAddress;
    int LocalPort;
    int RemotePort;
    LONG BytesOut;
    LONG BytesIn;
    LONG OutboundBandwidth;
    LONG InboundBandwidth;
    int Pass = 0;
    std::string CollectionTime;

};

Header "NetworkPerformanceScanner.h" 标题“NetworkPerformanceScanner.h”

#pragma once
#include <iostream>
#include <vector>
#include <sstream>
#include "NetworkPerformanceItem.h"
#include <iomanip>
#include <iostream>
#include <windows.h>
#include <winsock2.h>
#include <Ws2tcpip.h>
#include <iphlpapi.h>
#include <Tcpestats.h>
#include <stdlib.h>
#include <stdio.h>


using namespace std;

#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")

#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x)) 
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))

class NetworkPerformanceScanner
{
public:
    NetworkPerformanceScanner();
    ~NetworkPerformanceScanner();

    std::vector<NetworkPerformanceItem> ScanNetworkPerformance(int sampleId);
};

Source "NetworkPerformanceScanner.cpp" 来源“NetworkPerformanceScanner.cpp”

#include "stdafx.h"
    #include "NetworkPerformanceScanner.h"



NetworkPerformanceScanner::NetworkPerformanceScanner()
{

}


NetworkPerformanceScanner::~NetworkPerformanceScanner()
{
}

// TODO - implement TCP v6, UDP
std::vector<NetworkPerformanceItem> NetworkPerformanceScanner::ScanNetworkPerformance(int pass)
{

    std::vector<unsigned char> buffer;
    DWORD dwSize = sizeof(MIB_TCPTABLE_OWNER_PID);
    DWORD dwRetValue = 0;
    vector<NetworkPerformanceItem> networkPerformanceItems;

    // get local computer time with timezone offset
    auto time = std::time(nullptr);
    std::ostringstream timeStream;
    timeStream << std::put_time(std::localtime(&time), "%F %T%z");
    string collectionTime = timeStream.str();

    // repeat till buffer is big enough
    do
    {
        buffer.resize(dwSize, 0);
        dwRetValue = GetExtendedTcpTable(buffer.data(), &dwSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0);

    } while (dwRetValue == ERROR_INSUFFICIENT_BUFFER);

    if (dwRetValue == ERROR_SUCCESS)
    {
        // good case

        // cast to access element values
        PMIB_TCPTABLE_OWNER_PID ptTable = reinterpret_cast<PMIB_TCPTABLE_OWNER_PID>(buffer.data());

        cout << "Number of Entries: " << ptTable->dwNumEntries << endl << endl;


        // caution: array starts with index 0, count starts by 1
        for (DWORD i = 0; i < ptTable->dwNumEntries; i++)
        {
            NetworkPerformanceItem networkPerformanceItem;

            networkPerformanceItem.ProcessId = ptTable->table[i].dwOwningPid;
            networkPerformanceItem.State = ptTable->table[i].dwState;           

            cout << "PID: " << ptTable->table[i].dwOwningPid << endl;
            cout << "State: " << ptTable->table[i].dwState << endl;

            std::ostringstream localStream;
            localStream << (ptTable->table[i].dwLocalAddr & 0xFF)
                << "."
                << ((ptTable->table[i].dwLocalAddr >> 8) & 0xFF)
                << "."
                << ((ptTable->table[i].dwLocalAddr >> 16) & 0xFF)
                << "."
                << ((ptTable->table[i].dwLocalAddr >> 24) & 0xFF)
                << ":"
                << htons((unsigned short)ptTable->table[i].dwLocalPort);
            networkPerformanceItem.LocalAddress = localStream.str();
            networkPerformanceItem.LocalPort = ptTable->table[i].dwLocalPort;

            std::ostringstream remoteStream;
            remoteStream << (ptTable->table[i].dwRemoteAddr & 0xFF)
                << "."
                << ((ptTable->table[i].dwRemoteAddr >> 8) & 0xFF)
                << "."
                << ((ptTable->table[i].dwRemoteAddr >> 16) & 0xFF)
                << "."
                << ((ptTable->table[i].dwRemoteAddr >> 24) & 0xFF)
                << ":"
                << htons((unsigned short)ptTable->table[i].dwRemotePort);
            networkPerformanceItem.RemoteAddress = remoteStream.str();
            networkPerformanceItem.RemotePort = ptTable->table[i].dwRemotePort;

            MIB_TCPROW row;
            row.dwLocalAddr = ptTable->table[i].dwLocalAddr;
            row.dwLocalPort = ptTable->table[i].dwLocalPort;
            row.dwRemoteAddr = ptTable->table[i].dwRemoteAddr;
            row.dwRemotePort = ptTable->table[i].dwRemotePort;
            row.dwState = ptTable->table[i].dwState;
            void *processRow = &row;

            if (row.dwRemoteAddr != 0)
            {
                ULONG rosSize = 0, rodSize = 0;
                ULONG winStatus;
                PUCHAR ros = NULL, rod = NULL;
                rodSize = sizeof(TCP_ESTATS_DATA_ROD_v0);
                PTCP_ESTATS_DATA_ROD_v0 dataRod = { 0 };

                if (rosSize != 0) {
                    ros = (PUCHAR)malloc(rosSize);
                    if (ros == NULL) {
                        wprintf(L"\nOut of memory");
                        return networkPerformanceItems;
                    }
                    else
                        memset(ros, 0, rosSize); // zero the buffer
                }
                if (rodSize != 0) {
                    rod = (PUCHAR)malloc(rodSize);
                    if (rod == NULL) {
                        free(ros);
                        wprintf(L"\nOut of memory");
                        return networkPerformanceItems;
                    }
                    else
                        memset(rod, 0, rodSize); // zero the buffer
                }

                winStatus = GetPerTcpConnectionEStats((PMIB_TCPROW)&row, TcpConnectionEstatsData, NULL, 0, 0, ros, 0, rosSize, rod, 0, rodSize);

                dataRod = (PTCP_ESTATS_DATA_ROD_v0)rod;

                networkPerformanceItem.BytesIn = dataRod->DataBytesIn;
                networkPerformanceItem.BytesOut = dataRod->DataBytesOut;

                PTCP_ESTATS_BANDWIDTH_ROD_v0 bandwidthRod = { 0 };

                rodSize = sizeof(TCP_ESTATS_BANDWIDTH_ROD_v0);
                if (rodSize != 0) {
                    rod = (PUCHAR)malloc(rodSize);
                    if (rod == NULL) {
                        free(ros);
                        wprintf(L"\nOut of memory");
                        return networkPerformanceItems;
                    }
                    else
                        memset(rod, 0, rodSize); // zero the buffer
                }

                winStatus = GetPerTcpConnectionEStats((PMIB_TCPROW)&row,TcpConnectionEstatsBandwidth, NULL, 0, 0, ros, 0, rosSize, rod, 0, rodSize);

                bandwidthRod = (PTCP_ESTATS_BANDWIDTH_ROD_v0)rod;
                networkPerformanceItem.OutboundBandwidth = bandwidthRod->OutboundBandwidth;
                networkPerformanceItem.InboundBandwidth = bandwidthRod->InboundBandwidth;

            }
            networkPerformanceItem.Pass = pass;
            networkPerformanceItem.CollectionTime = collectionTime;
            networkPerformanceItems.push_back(networkPerformanceItem);
        }
    }
    else
    {
        // bad case, do some sh*t here
    }

    return networkPerformanceItems;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM