You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Windows 7下如何记录网络带宽及特定IP的网络统计信息?

我完全懂你这种搜了好几天,结果连这么基础的需求都找不到现成简单工具的挫败感!在Windows 7下记录特定IP的UDP/TCP带宽和错误信息,确实有不少坑,比如NetMon经常遇到权限或兼容性问题。下面给你几个靠谱的解决方案,涵盖系统临时方案和你要的C#/C++编程实现:

解决方案:Windows 7下记录特定IP的网络统计信息

一、应急方案:系统自带命令行工具

如果暂时不想写代码,可以试试netsh配合tracerpt,虽然灵活性不如编程,但胜在无需额外工具:

  • 启动特定IP的流量捕获(替换成你的目标IP):
    netsh trace start capture=yes IPv4.Address=192.168.1.100 tracefile=C:\nettrace.etl
    
  • 停止捕获:
    netsh trace stop
    
  • 解析捕获文件为CSV格式(方便后续分析):
    tracerpt C:\nettrace.etl -o C:\netstats.csv
    

不过这个方案无法实时统计带宽,适合事后分析,如果你需要持续数小时的实时监控,还是编程方案更合适。

二、C# 实时统计方案(基于SharpPcap)

SharpPcap是WinPcap的.NET封装库,上手简单,适合快速开发。

步骤1:安装依赖

在NuGet中搜索并安装SharpPcapPacketDotNet两个包。

步骤2:代码示例(实时统计带宽+错误)

using System;
using System.Threading;
using SharpPcap;
using PacketDotNet;

class NetworkStatsCollector
{
    // 线程安全的统计变量
    private static readonly long[] _counters = new long[6];
    private const int TcpRecvIdx = 0;
    private const int TcpSendIdx = 1;
    private const int TcpErrorIdx = 2;
    private const int UdpRecvIdx = 3;
    private const int UdpSendIdx = 4;
    private const int UdpErrorIdx = 5;
    
    private static string _targetIp = "192.168.1.100"; // 替换为你的目标IP

    static void Main(string[] args)
    {
        // 获取所有可用网卡
        var devices = CaptureDeviceList.Instance;
        if (devices.Count == 0)
        {
            Console.WriteLine("未找到可用网络适配器,请检查权限!");
            return;
        }

        // 选择第一个网卡(可以改成让用户选择)
        var device = devices[0];
        Console.WriteLine($"正在使用网卡: {device.Description}");

        // 打开网卡并设置过滤规则(只捕获目标IP的TCP/UDP流量)
        device.Open(DeviceMode.Promiscuous, 1000);
        device.Filter = $"host {_targetIp} and (tcp or udp)";

        // 注册包捕获事件
        device.OnPacketArrival += HandlePacket;

        // 启动统计打印线程
        var statsThread = new Thread(PrintStatsLoop);
        statsThread.Start();

        Console.WriteLine("开始捕获...按任意键停止");
        device.StartCapture();
        Console.ReadKey();

        // 停止捕获并清理资源
        device.StopCapture();
        device.Close();
        statsThread.Abort();
        Console.WriteLine("\n捕获已停止");
    }

    private static void HandlePacket(object sender, CaptureEventArgs e)
    {
        var packet = Packet.ParsePacket(e.Packet.LinkLayerType, e.Packet.Data);
        var ipPacket = packet.Extract<IpPacket>();
        if (ipPacket == null) return;

        // 判断流量方向(发送/接收)
        bool isSent = ipPacket.SourceAddress.ToString() == _targetIp;

        // 处理TCP包
        var tcpPacket = packet.Extract<TcpPacket>();
        if (tcpPacket != null)
        {
            if (tcpPacket.HasError) Interlocked.Increment(ref _counters[TcpErrorIdx]);
            var counterIdx = isSent ? TcpSendIdx : TcpRecvIdx;
            Interlocked.Add(ref _counters[counterIdx], tcpPacket.TotalPacketLength);
            return;
        }

        // 处理UDP包
        var udpPacket = packet.Extract<UdpPacket>();
        if (udpPacket != null)
        {
            if (ipPacket.HasError) Interlocked.Increment(ref _counters[UdpErrorIdx]);
            var counterIdx = isSent ? UdpSendIdx : UdpRecvIdx;
            Interlocked.Add(ref _counters[counterIdx], udpPacket.TotalPacketLength);
        }
    }

    private static void PrintStatsLoop()
    {
        while (true)
        {
            Thread.Sleep(1000);
            Console.Clear();
            Console.WriteLine($"目标IP: {_targetIp}");
            Console.WriteLine("=================== TCP 统计 ===================");
            Console.WriteLine($"接收字节: {_counters[TcpRecvIdx] / 1024:N0} KB | 发送字节: {_counters[TcpSendIdx] / 1024:N0} KB");
            Console.WriteLine($"错误数: {_counters[TcpErrorIdx]}");
            Console.WriteLine("=================== UDP 统计 ===================");
            Console.WriteLine($"接收字节: {_counters[UdpRecvIdx] / 1024:N0} KB | 发送字节: {_counters[UdpSendIdx] / 1024:N0} KB");
            Console.WriteLine($"错误数: {_counters[UdpErrorIdx]}");
        }
    }
}

注意事项

  • 必须以管理员身份运行程序,否则没有网卡访问权限
  • 如果SharpPcap找不到网卡,需要安装WinPcap驱动(兼容Windows 7)

三、C++ 底层实现方案(基于WinPcap)

如果需要更低开销的底层实现,可以直接用WinPcap原生API。

步骤1:准备开发环境

下载WinPcap开发包,配置项目的Include路径和链接库(wpcap.lib)。

步骤2:代码示例

#include <pcap.h>
#include <iostream>
#include <thread>
#include <atomic>
#include <cstring>

// 线程安全统计变量
std::atomic_long tcp_recv = 0, tcp_send = 0;
std::atomic_int tcp_err = 0;
std::atomic_long udp_recv = 0, udp_send = 0;
std::atomic_int udp_err = 0;
std::string target_ip = "192.168.1.100";

// 解析IP包并统计
void parse_ip_packet(const u_char* packet, int len, bool is_sent) {
    // IP头结构简化定义
    struct ip_hdr {
        u_char ver_ihl;
        u_char tos;
        u_short tlen;
        u_short id;
        u_short flags_off;
        u_char ttl;
        u_char proto;
        u_short crc;
        u_char saddr[4];
        u_char daddr[4];
    };

    ip_hdr* ip = (ip_hdr*)(packet + 14); // 跳过以太网头
    char src_ip[16], dst_ip[16];
    sprintf(src_ip, "%d.%d.%d.%d", ip->saddr[0], ip->saddr[1], ip->saddr[2], ip->saddr[3]);
    sprintf(dst_ip, "%d.%d.%d.%d", ip->daddr[0], ip->daddr[1], ip->daddr[2], ip->daddr[3]);

    // 过滤非目标IP的流量
    if (strcmp(src_ip, target_ip.c_str()) != 0 && strcmp(dst_ip, target_ip.c_str()) != 0)
        return;

    // 检查IP层错误(简化示例,可自行实现校验和验证)
    bool ip_error = false;

    // 处理TCP
    if (ip->proto == 6) {
        int tcp_total_len = ntohs(ip->tlen) - ((ip->ver_ihl & 0x0F) * 4);
        if (ip_error) tcp_err++;
        is_sent ? tcp_send += tcp_total_len : tcp_recv += tcp_total_len;
    }
    // 处理UDP
    else if (ip->proto == 17) {
        int udp_total_len = ntohs(*(u_short*)(packet + 14 + 20 + 4));
        if (ip_error) udp_err++;
        is_sent ? udp_send += udp_total_len : udp_recv += udp_total_len;
    }
}

// 包捕获回调函数
void packet_handler(u_char* local_mac, const pcap_pkthdr* hdr, const u_char* packet) {
    // 判断流量方向:目标MAC是否为本机MAC
    bool is_sent = memcmp(packet, local_mac, 6) != 0;
    parse_ip_packet(packet, hdr->len, is_sent);
}

// 打印统计线程
void print_stats_loop() {
    while (true) {
        std::this_thread::sleep_for(std::chrono::seconds(1));
        system("cls");
        std::cout << "目标IP: " << target_ip << "\n";
        std::cout << "TCP 统计: 接收 " << tcp_recv / 1024 << " KB | 发送 " << tcp_send / 1024 << " KB | 错误 " << tcp_err << "\n";
        std::cout << "UDP 统计: 接收 " << udp_recv / 1024 << " KB | 发送 " << udp_send / 1024 << " KB | 错误 " << udp_err << "\n";
    }
}

int main() {
    pcap_if_t* alldevs;
    char errbuf[PCAP_ERRBUF_SIZE];
    if (pcap_findalldevs(&alldevs, errbuf) == -1) {
        std::cerr << "获取网卡失败: " << errbuf << "\n";
        return 1;
    }

    // 选择网卡(简化示例,直接用第一个)
    pcap_if_t* dev = alldevs;
    u_char local_mac[6];
    // 获取本机MAC地址
    for (pcap_addr_t* addr = dev->addresses; addr; addr = addr->next) {
        if (addr->addr->sa_family == AF_LINK) {
            memcpy(local_mac, ((struct sockaddr_ll*)addr->addr)->sll_addr, 6);
            break;
        }
    }

    // 打开网卡
    pcap_t* handle = pcap_open_live(dev->name, 65536, 1, 1000, errbuf);
    if (!handle) {
        std::cerr << "打开网卡失败: " << errbuf << "\n";
        pcap_freealldevs(alldevs);
        return 1;
    }

    // 设置过滤规则
    char filter[100];
    sprintf(filter, "host %s and (tcp or udp)", target_ip.c_str());
    struct bpf_program fp;
    bpf_u_int32 net;
    pcap_lookupnet(dev->name, &net, nullptr, errbuf);
    pcap_compile(handle, &fp, filter, 0, net);
    pcap_setfilter(handle, &fp);

    // 启动统计线程
    std::thread stats_thread(print_stats_loop);

    std::cout << "开始捕获...按任意键停止\n";
    pcap_loop(handle, 0, packet_handler, local_mac);

    // 清理资源
    pcap_close(handle);
    pcap_freealldevs(alldevs);
    stats_thread.detach();
    std::cout << "\n捕获已停止\n";
    return 0;
}

注意事项

  • 同样需要管理员权限运行
  • 如果需要更精确的错误统计,可实现IP/TCP/UDP的校验和验证逻辑

四、低开销替代方案:Windows Filtering Platform (WFP)

如果长期运行且对性能要求高,可以用Windows原生的WFP框架。WFP无需抓包,直接在内核层过滤统计流量,开销极低,但API相对复杂,适合有Windows网络编程经验的开发者。核心思路是注册过滤规则匹配目标IP,在回调函数中统计字节数和错误。

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

火山引擎 最新活动