A:增加GetIfTable2数据访问

This commit is contained in:
jimmy committed 2025-07-11 16:22:50 +08:00
1 parent 77f46fcab2
commit d484c85abb
4 files changed
+346

No files matched your search

@@ -0,0 +1,79 @@
using NetVizor.Common.Utils;
using NUnit.Framework;
using System;
using System.Linq;
using System.Threading;
namespace Common.Test
{
[TestFixture]
public class NetworkInfoUtilTest
{
[Test]
public void TestGetAllInterfaces()
{
TestContext.Progress.WriteLine("--- Network Interface List ---");
// 1. Get all network interface information
var interfaces = NetworkInfoUtil.GetAllInterfaces();
Assert.IsNotNull(interfaces);
Assert.IsTrue(interfaces.Count > 0, "No network interfaces found.");
foreach (var iface in interfaces)
{
TestContext.Progress.WriteLine($"Index: {iface.Index}, Alias: {iface.Alias}, Status: {iface.Status}");
TestContext.Progress.WriteLine($" Description: {iface.Description}");
TestContext.Progress.WriteLine($" MAC: {iface.MacAddress}, Type: {iface.Type}");
TestContext.Progress.WriteLine(
$" Bytes Sent: {iface.BytesSent}, Bytes Received: {iface.BytesReceived}\n");
}
}
[Test]
public void TestMonitorActiveInterfaceSpeed()
{
var interfaces = NetworkInfoUtil.GetAllInterfaces();
// 2. Select an active interface to monitor real-time speed
var activeInterface = interfaces.FirstOrDefault(i =>
i.Status == System.Net.NetworkInformation.OperationalStatus.Up
&& i.Type != System.Net.NetworkInformation.NetworkInterfaceType.Loopback
&& i.Type != System.Net.NetworkInformation.NetworkInterfaceType.Tunnel);
if (activeInterface == null)
{
Assert.Inconclusive("No active, non-loopback interface found to monitor. Test skipped.");
return; // Skip test if no suitable interface is found
}
TestContext.Progress.WriteLine($"--- Monitoring real-time speed for: {activeInterface.Alias} ---");
var speedMonitor = new NetworkSpeedMonitor(activeInterface);
// 3. Periodically update and display the network speed
TestContext.Progress.WriteLine("Monitoring for 5 seconds...");
for (int i = 0; i < 5; i++)
{
Thread.Sleep(1000); // Update every second
speedMonitor.Update();
string downSpeed = FormatSpeed(speedMonitor.DownloadSpeedBps);
string upSpeed = FormatSpeed(speedMonitor.UploadSpeedBps);
TestContext.Progress.WriteLine(
$"Time: {DateTime.Now:HH:mm:ss} | Download: {downSpeed} | Upload: {upSpeed}");
}
Assert.IsTrue(speedMonitor.DownloadSpeedBps >= 0);
Assert.IsTrue(speedMonitor.UploadSpeedBps >= 0);
}
private static string FormatSpeed(double bytesPerSecond)
{
if (bytesPerSecond < 1024)
return $"{bytesPerSecond:F2} B/s";
if (bytesPerSecond < 1024 * 1024)
return $"{bytesPerSecond / 1024:F2} KB/s";
return $"{bytesPerSecond / (1024 * 1024):F2} MB/s";
}
}
}
@@ -0,0 +1,193 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Net.NetworkInformation;
using System.Runtime.InteropServices;
using NetVizor.Common.Models;
namespace NetVizor.Common.Utils
{
/// <summary>
/// Provides utility methods to retrieve network interface information
/// using the Windows IP Helper API (iphlpapi.dll).
/// This class does not require administrator privileges.
/// </summary>
public static class NetworkInfoUtil
{
#region P/Invoke Definitions
private const int ERROR_SUCCESS = 0;
private const int MAX_INTERFACE_NAME_LEN = 256;
private const int MAXLEN_PHYSADDR = 8;
private const int MAXLEN_IFDESCR = 256;
[DllImport("iphlpapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern uint GetIfTable2(out IntPtr pIfTable);
[DllImport("iphlpapi.dll", SetLastError = true)]
private static extern void FreeMibTable(IntPtr pMibTable);
private enum TunnelType
{
TUNNEL_TYPE_NONE = 0,
TUNNEL_TYPE_OTHER = 1,
TUNNEL_TYPE_DIRECT = 2,
TUNNEL_TYPE_6TO4 = 11,
TUNNEL_TYPE_ISATAP = 13,
TUNNEL_TYPE_TEREDO = 14,
TUNNEL_TYPE_IPHTTPS = 15
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct MIB_IF_ROW2
{
public long InterfaceLuid;
public uint InterfaceIndex;
public Guid InterfaceGuid;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_INTERFACE_NAME_LEN + 1)]
public string Alias;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAXLEN_IFDESCR + 1)]
public string Description;
public uint PhysicalAddressLength;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAXLEN_PHYSADDR)]
public byte[] PhysicalAddress;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAXLEN_PHYSADDR)]
public byte[] PermanentPhysicalAddress;
public uint Mtu;
public NetworkInterfaceType Type;
public TunnelType TunnelType;
public uint MediaConnectState;
public uint MediaDuplexState;
public uint InterfaceAndOperStatusFlags;
public OperationalStatus OperStatus;
public uint AdminStatus;
public uint NetLuidIndex;
public uint NdisMedium;
public uint NdisPhysicalMedium;
public uint HardareInterface;
// --- Start of Corrected Fields ---
public ulong ReceiveLinkSpeed;
public ulong TransmitLinkSpeed;
// --- End of Corrected Fields ---
public ulong OutOctets;
public ulong InOctets;
public ulong OutUcastPkts;
public ulong InUcastPkts;
public ulong OutNUcastPkts;
public ulong InNUcastPkts;
public ulong OutDiscards;
public ulong InDiscards;
public ulong OutErrors;
public ulong InErrors;
public ulong OutUcastOctets;
public ulong InUcastOctets;
public ulong OutMulticastOctets;
public ulong InMulticastOctets;
public ulong OutBroadcastOctets;
public ulong InBroadcastOctets;
public uint OutQLen;
}
[StructLayout(LayoutKind.Sequential)]
private struct MIB_IF_TABLE2
{
public uint NumEntries;
// The Table field is a placeholder here. We'll calculate its position manually.
}
#endregion
/// <summary>
/// Gets a list of all network interfaces on the system.
/// </summary>
/// <returns>A list of NetworkInterfaceInfo objects.</returns>
/// <exception cref="Win32Exception">Thrown if the underlying Windows API call fails.</exception>
public static List<NetworkInterfaceInfo> GetAllInterfaces()
{
IntPtr pIfTable = IntPtr.Zero;
try
{
uint result = GetIfTable2(out pIfTable);
if (result != ERROR_SUCCESS)
{
throw new Win32Exception((int)result);
}
var ifTable = (MIB_IF_TABLE2)Marshal.PtrToStructure(pIfTable, typeof(MIB_IF_TABLE2));
var interfaces = new List<NetworkInterfaceInfo>((int)ifTable.NumEntries);
IntPtr currentPtr = new IntPtr(pIfTable.ToInt64() + Marshal.SizeOf(typeof(uint)));
for (int i = 0; i < ifTable.NumEntries; i++)
{
var row = (MIB_IF_ROW2)Marshal.PtrToStructure(currentPtr, typeof(MIB_IF_ROW2));
interfaces.Add(MapRowToInterfaceInfo(row));
currentPtr = new IntPtr(currentPtr.ToInt64() + Marshal.SizeOf(typeof(MIB_IF_ROW2)));
}
return interfaces;
}
finally
{
if (pIfTable != IntPtr.Zero)
{
FreeMibTable(pIfTable);
}
}
}
/// <summary>
/// Gets detailed information for a specific network interface by its index.
/// </summary>
/// <param name="interfaceIndex">The index of the interface to retrieve.</param>
/// <returns>A NetworkInterfaceInfo object, or null if not found.</returns>
public static NetworkInterfaceInfo? GetInterfaceByIndex(uint interfaceIndex)
{
var allInterfaces = GetAllInterfaces();
foreach (var iface in allInterfaces)
{
if (iface.Index == interfaceIndex)
{
return iface;
}
}
return null;
}
private static NetworkInterfaceInfo MapRowToInterfaceInfo(MIB_IF_ROW2 row)
{
// Guard against invalid address length reported by the API
int macAddrLen = (int)Math.Min(row.PhysicalAddressLength, (uint)MAXLEN_PHYSADDR);
var macBytes = new byte[macAddrLen];
if (macAddrLen > 0)
{
Array.Copy(row.PhysicalAddress, macBytes, macAddrLen);
}
return new NetworkInterfaceInfo
{
Index = row.InterfaceIndex,
InterfaceId = row.InterfaceGuid.ToString(),
Alias = row.Alias,
Description = row.Description,
Type = row.Type,
Status = row.OperStatus,
Speed = row.ReceiveLinkSpeed, // Correctly use the speed field from the struct
MacAddress = macAddrLen > 0 ? BitConverter.ToString(macBytes).Replace('-', ':') : string.Empty,
BytesSent = (long)row.OutOctets,
BytesReceived = (long)row.InOctets
};
}
}
}
@@ -0,0 +1,72 @@
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using NetVizor.Common.Models;
namespace NetVizor.Common.Utils
{
/// <summary>
/// Monitors the real-time network speed (upload/download) for a specific network interface.
/// </summary>
public class NetworkSpeedMonitor
{
private readonly uint _interfaceIndex;
private long _lastBytesSent;
private long _lastBytesReceived;
private DateTime _lastUpdateTime;
/// <summary>
/// Gets the real-time download speed in bytes per second.
/// </summary>
public double DownloadSpeedBps { get; private set; }
/// <summary>
/// Gets the real-time upload speed in bytes per second.
/// </summary>
public double UploadSpeedBps { get; private set; }
/// <summary>
/// Initializes a new instance of the NetworkSpeedMonitor for a given interface.
/// </summary>
/// <param name="interfaceInfo">The network interface to monitor.</param>
public NetworkSpeedMonitor(NetworkInterfaceInfo interfaceInfo)
{
_interfaceIndex = interfaceInfo.Index;
_lastBytesSent = interfaceInfo.BytesSent;
_lastBytesReceived = interfaceInfo.BytesReceived;
_lastUpdateTime = DateTime.UtcNow;
}
/// <summary>
/// Updates the speed calculation. This method should be called periodically.
/// </summary>
public void Update()
{
var currentInterfaceInfo = NetworkInfoUtil.GetInterfaceByIndex(_interfaceIndex);
if (currentInterfaceInfo == null)
{
DownloadSpeedBps = 0;
UploadSpeedBps = 0;
return;
}
var currentTime = DateTime.UtcNow;
var timeSpan = (currentTime - _lastUpdateTime).TotalSeconds;
if (timeSpan <= 0)
{
return; // Avoid division by zero if called too quickly
}
long bytesSent = currentInterfaceInfo.BytesSent;
long bytesReceived = currentInterfaceInfo.BytesReceived;
UploadSpeedBps = (bytesSent - _lastBytesSent) / timeSpan;
DownloadSpeedBps = (bytesReceived - _lastBytesReceived) / timeSpan;
_lastBytesSent = bytesSent;
_lastBytesReceived = bytesReceived;
_lastUpdateTime = currentTime;
}
}
}
@@ -60,6 +60,8 @@
&lt;TestId&gt;NUnit3x::B3F481C9-B351-449C-AE2B-CDEC29BD5DCC::net8.0::Common.Test.Tests.Test1&lt;/TestId&gt;&#xD;
&lt;TestId&gt;NUnit3x::B3F481C9-B351-449C-AE2B-CDEC29BD5DCC::net8.0::Common.Test.Logger.LogTest.Test1&lt;/TestId&gt;&#xD;
&lt;TestId&gt;NUnit3x::107A4E9F-39C9-4501-9323-73C9B62932EF::net8.0::Utils.ETW.Test.Tests.Test1&lt;/TestId&gt;&#xD;
&lt;TestId&gt;NUnit3x::B3F481C9-B351-449C-AE2B-CDEC29BD5DCC::net8.0::Common.Test.NetworkInfoUtilTest.TestGetAllInterfaces&lt;/TestId&gt;&#xD;
&lt;TestId&gt;NUnit3x::B3F481C9-B351-449C-AE2B-CDEC29BD5DCC::net8.0::Common.Test.NetworkInfoUtilTest.TestMonitorActiveInterfaceSpeed&lt;/TestId&gt;&#xD;
&lt;/TestAncestor&gt;&#xD;
&lt;/SessionState&gt;</s:String>
</wpf:ResourceDictionary>