A:增加GetIfTable2数据访问
This commit is contained in:
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 @@
|
||||
<TestId>NUnit3x::B3F481C9-B351-449C-AE2B-CDEC29BD5DCC::net8.0::Common.Test.Tests.Test1</TestId>
|
||||
<TestId>NUnit3x::B3F481C9-B351-449C-AE2B-CDEC29BD5DCC::net8.0::Common.Test.Logger.LogTest.Test1</TestId>
|
||||
<TestId>NUnit3x::107A4E9F-39C9-4501-9323-73C9B62932EF::net8.0::Utils.ETW.Test.Tests.Test1</TestId>
|
||||
<TestId>NUnit3x::B3F481C9-B351-449C-AE2B-CDEC29BD5DCC::net8.0::Common.Test.NetworkInfoUtilTest.TestGetAllInterfaces</TestId>
|
||||
<TestId>NUnit3x::B3F481C9-B351-449C-AE2B-CDEC29BD5DCC::net8.0::Common.Test.NetworkInfoUtilTest.TestMonitorActiveInterfaceSpeed</TestId>
|
||||
</TestAncestor>
|
||||
</SessionState></s:String>
|
||||
</wpf:ResourceDictionary>
|
||||
Reference in new issue
Block a user