首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 呼叫 IpHlpApi 取得網路介面卡資訊與流量統計

     編輯:關於C語言

使用 GetIfTable API 監控網路流量

.NET Framework 未直接提供取得網卡即時流量的類別,可透過 P/Invoke 呼叫 IpHlpApi.dll 的 GetIfTable 函式,取得 MIB_IF_TABLE 結構,包含每張網卡的位元組收發計數、速度、類型、MAC 位址等資訊。

API 定義與結構對應

using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Text;

public class NetworkMonitor
{
    [DllImport("IpHlpApi.dll", SetLastError = true)]
    private static extern uint GetIfTable(byte[] pIfTable, ref uint pdwSize, bool bOrder);

    // 對應 MIB_IFROW 結構
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    private struct MIB_IFROW
    {
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
        public string wszName;
        public uint dwIndex;
        public uint dwType;
        public uint dwMtu;
        public uint dwSpeed;
        public uint dwPhysAddrLen;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
        public byte[] bPhysAddr;
        public uint dwAdminStatus;
        public uint dwOperStatus;
        public uint dwLastChange;
        public uint dwInOctets;
        public uint dwInUcastPkts;
        public uint dwInNUcastPkts;
        public uint dwInDiscards;
        public uint dwInErrors;
        public uint dwInUnknownProtos;
        public uint dwOutOctets;
        public uint dwOutUcastPkts;
        public uint dwOutNUcastPkts;
        public uint dwOutDiscards;
        public uint dwOutErrors;
        public uint dwOutQLen;
        public uint dwDescrLen;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
        public byte[] bDescr;
    }

    // 對應 MIB_IFTABLE 結構
    [StructLayout(LayoutKind.Sequential)]
    private struct MIB_IFTABLE
    {
        public uint dwNumEntries;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] // 實際大小由 dwNumEntries 決定
        public MIB_IFROW[] table;
    }
}

取得所有網卡資訊

public class NetInfo
{
    public string Name { get; set; }
    public string Description { get; set; }
    public string MacAddress { get; set; }
    public uint Speed { get; set; } // bps
    public uint InBytes { get; set; }
    public uint OutBytes { get; set; }
    public OperationalStatus Status { get; set; }
}

public static List GetAllNetworkInfo()
{
    List list = new List();

    // 先取得緩衝區大小
    uint size = 0;
    uint ret = GetIfTable(null, ref size, false);
    if (ret != 122) // ERROR_INSUFFICIENT_BUFFER
        throw new System.ComponentModel.Win32Exception((int)ret);

    byte[] buffer = new byte[size];
    ret = GetIfTable(buffer, ref size, false);
    if (ret != 0)
        throw new System.ComponentModel.Win32Exception((int)ret);

    // 將 byte[] 反序列化為結構
    GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
    try
    {
        IntPtr ptr = handle.AddrOfPinnedObject();
        MIB_IFTABLE table = (MIB_IFTABLE)Marshal.PtrToStructure(ptr, typeof(MIB_IFTABLE));

        // 重新計算陣列實際大小
        int rowSize = Marshal.SizeOf(typeof(MIB_IFROW));
        table.table = new MIB_IFROW[table.dwNumEntries];
        IntPtr rowPtr = new IntPtr(ptr.ToInt64() + Marshal.SizeOf(typeof(uint))); // 跳過 dwNumEntries

        for (int i = 0; i < table.dwNumEntries; i++)
        {
            MIB_IFROW row = (MIB_IFROW)Marshal.PtrToStructure(rowPtr, typeof(MIB_IFROW));
            table.table[i] = row;
            rowPtr = new IntPtr(rowPtr.ToInt64() + rowSize);
        }

        // 轉換為友善模型
        foreach (var row in table.table)
        {
            list.Add(new NetInfo
            {
                Name = Encoding.ASCII.GetString(row.wszName).TrimEnd('\0'),
                Description = Encoding.ASCII.GetString(row.bDescr, 0, (int)row.dwDescrLen).TrimEnd('\0'),
                MacAddress = BitConverter.ToString(row.bPhysAddr, 0, (int)row.dwPhysAddrLen).Replace('-', ':'),
                Speed = row.dwSpeed,
                InBytes = row.dwInOctets,
                OutBytes = row.dwOutOctets,
                Status = (OperationalStatus)row.dwOperStatus
            });
        }
    }
    finally
    {
        handle.Free();
    }
    return list;
}

使用範例:即時顯示下載/上傳速度

var prev = GetAllNetworkInfo();
while (true)
{
    Thread.Sleep(1000);
    var curr = GetAllNetworkInfo();
    for (int i = 0; i < curr.Count; i++)
    {
        if (curr[i].Name == prev[i].Name)
        {
            double downKB = (curr[i].InBytes - prev[i].InBytes) / 1024.0;
            double upKB = (curr[i].OutBytes - prev[i].OutBytes) / 1024.0;
            Console.WriteLine($"{curr[i].Description} ↓{downKB:F1} KB/s ↑{upKB:F1} KB/s");
        }
    }
    prev = curr;
}

注意事項

  • GetIfTable 僅支援 IPv4 介面,IPv6 請用 GetIfTable2 (Vista+)。
  • 計數器為 32 位元無號整數,高流量環境會溢位,需處理溢位邏輯或改用 64 位元版本。
  • 需參考 System.Management 取得更豐富資訊(如 IPv6、DHCP 狀態)。
  • 執行需管理員權限才能存取完整介面資訊。

替代方案: .NET Core / .NET 5+ 可使用 System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces() 取得類似資料,跨平台且無需 P/Invoke。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved