基于C#实现WiFi信号强度扫描的完整代码
作者:jllllyuz
这篇文章主要介绍了基于C#实现WiFi信号强度扫描的完整代码,主要功能包括:信号强度检测、距离估算和实时监控
一、核心功能实现
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Runtime.InteropServices;
using System.Timers;
using SimpleWifi;
public class WifiScanner : IDisposable
{
private Wifi _wifi;
private Timer _scanTimer;
private Dictionary<string, (int rssi, double distance)> _scanResults = new();
public event EventHandler<ScanResultsUpdatedEventArgs> ResultsUpdated;
public WifiScanner()
{
_wifi = new Wifi();
InitializeScanTimer(5000); // 每5秒扫描一次
}
// 初始化定时扫描
private void InitializeScanTimer(int interval)
{
_scanTimer = new Timer(interval);
_scanTimer.Elapsed += async (s, e) => await ScanNetworks();
}
// 执行扫描操作
private async Task ScanNetworks()
{
try
{
var accessPoints = await _wifi.GetAccessPointsAsync();
var results = new List<ScanResult>();
foreach (var ap in accessPoints)
{
if (ap.SignalStrength > -100) // 过滤无效信号
{
double distance = CalculateDistance(ap.SignalStrength);
results.Add(new ScanResult
{
SSID = ap.Name,
RSSI = ap.SignalStrength,
Distance = distance,
Channel = ap.Channel,
Security = ap.IsSecure
});
}
}
_scanResults = results.ToDictionary(x => x.SSID, x => (x.RSSI, x.Distance));
ResultsUpdated?.Invoke(this, new ScanResultsUpdatedEventArgs(_scanResults.Values.ToList()));
}
catch (Exception ex)
{
HandleScanError(ex);
}
}
// 信号强度转距离估算(经验公式)
private double CalculateDistance(int rssi)
{
const double referenceDistance = 1.0; // 参考距离(米)
const int referenceRSSI = -30; // 参考信号强度
if (rssi >= referenceRSSI) return 0.1; // 过近时返回固定值
double pathLoss = referenceRSSI - rssi;
return Math.Pow(10, pathLoss / 20) * referenceDistance;
}
// 显示结果
public void DisplayResults()
{
Console.WriteLine("WiFi信号扫描结果:");
foreach (var result in _scanResults.Values)
{
Console.WriteLine($"SSID: {result.SSID,-15} " +
$"信号强度: {result.RSSI}dBm " +
$"估算距离: {result.Distance.ToString("0.1f")}m " +
$"信道: {result.Channel} " +
$"加密: {(result.Security ? "是" : "否")}");
}
}
// 释放资源
public void Dispose()
{
_scanTimer?.Dispose();
_wifi?.Dispose();
}
}
public class ScanResult
{
public string SSID { get; set; }
public int RSSI { get; set; }
public double Distance { get; set; }
public int Channel { get; set; }
public bool Security { get; set; }
}
public class ScanResultsUpdatedEventArgs : EventArgs
{
public List<ScanResult> Results { get; }
public ScanResultsUpdatedEventArgs(List<ScanResult> results)
{
Results = results;
}
}二、关键功能说明
1. 信号强度检测
// 获取所有可用网络
var accessPoints = await _wifi.GetAccessPointsAsync();
// 解析关键信息
foreach (var ap in accessPoints)
{
Console.WriteLine($"SSID: {ap.Name}");
Console.WriteLine($"信号强度: {ap.SignalStrength}%"); // 百分比强度
Console.WriteLine($"实际dBm值: {ConvertToDbm(ap.SignalStrength)}dBm");
}
// 百分比转dBm转换方法
private int ConvertToDbm(int percentage)
{
return (int)((percentage / 2.0) - 100);
}2. 距离估算算法
// 改进型距离估算(考虑环境因素)
private double CalculateDistance(int rssi)
{
const double txPower = -59; // 发射功率(dBm)
const double n = 2.7; // 路径损耗指数
double ratio = rssi * 1.0 / txPower;
if (ratio < 1) return Math.Pow(ratio, 10);
else return 0.89976 * Math.Pow(ratio, 7.7095) + 0.111;
}3. 实时监控界面(WinForm示例)
public partial class MainForm : Form
{
private WifiScanner _scanner;
private DataGridView _dataGridView;
public MainForm()
{
InitializeComponent();
InitializeComponents();
_scanner = new WifiScanner();
_scanner.ResultsUpdated += OnResultsUpdated;
}
private void InitializeComponents()
{
_dataGridView = new DataGridView { Dock = DockStyle.Fill };
_dataGridView.Columns.AddRange(
new DataGridViewTextBoxColumn { Name = "SSID", HeaderText = "网络名称" },
new DataGridViewTextBoxColumn { Name = "SignalStrength", HeaderText = "信号强度(dBm)" },
new DataGridViewTextBoxColumn { Name = "Distance", HeaderText = "估算距离(m)" }
);
Controls.Add(_dataGridView);
}
private void OnResultsUpdated(object sender, ScanResultsUpdatedEventArgs e)
{
_dataGridView.Invoke((MethodInvoker)delegate {
_dataGridView.DataSource = e.Results;
});
}
}三、工程实践要点
1. 权限配置
<!-- app.manifest --> <requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
2. 性能优化
- 批量扫描:合并多个扫描结果减少系统调用
- 数据缓存:使用
ConcurrentDictionary存储历史数据 - 异步处理:采用
async/await避免界面卡顿
3. 高级功能扩展
// 信道干扰分析
public Dictionary<int, int> GetChannelUtilization()
{
return _scanResults.Values
.GroupBy(x => x.Channel)
.ToDictionary(g => g.Key, g => g.Count());
}
// 热力图生成
public Bitmap GenerateHeatmap()
{
// 使用GDI+绘制信号强度分布
}四、部署与使用
1. NuGet依赖
Install-Package SimpleWifi.netstandard.Lsh Install-Package LiveCharts.WinForms
2. 运行示例
var scanner = new WifiScanner();
scanner.ResultsUpdated += (s, e) =>
{
Console.WriteLine($"检测到 {e.Results.Count} 个网络");
e.Results.OrderByDescending(r => r.SignalStrength).Take(3).ToList().ForEach(r =>
Console.WriteLine($"最强信号: {r.SSID} ({r.SignalStrength}dBm)"));
};
scanner.StartContinuousScan();五、调试与校准
1. 日志记录
public static class Logger
{
public static void LogSignalData(int rssi, double distance)
{
File.AppendAllText("wifi_log.txt",
$"{DateTime.Now:yyyy-MM-dd HH:mm:ss} | RSSI:{rssi} | Distance:{distance}m\n");
}
}2. 精度校准
// 校准参数
private static double _calibrationFactor = 1.2;
// 带校准的距离计算
public double CalibratedDistance(int rssi)
{
double rawDistance = CalculateDistance(rssi);
return rawDistance * _calibrationFactor;
}六、界面增强建议
信号强度可视化
// 使用LiveCharts绘制实时波形
var chart = new CartesianChart();
chart.Series = new SeriesCollection
{
new LineSeries
{
Values = new ChartValues<double>(_scanResults.Values.Select(x => x.SignalStrength))
}
};设备定位功能
public Point CalculatePosition()
{
// 三角定位算法实现
var accessPoints = _scanResults.Values.ToList();
if (accessPoints.Count < 3) return Point.Empty;
// 实现三边测量算法...
}七、知识扩展
在 C# 中扫描 WiFi 信号强度,最直接的方法是调用 Windows 系统底层的 Wlanapi.dll。这需要用到平台调用(P/Invoke)技术,代码量稍大,但能提供最底层的控制和最高的执行效率。为了让代码更简洁、更易维护,更推荐的方案是使用社区开发者封装好的类库,如 Managed Wifi API 或 SimpleWifi。下面我将按两种方式分别介绍。
方案一:使用 P/Invoke 调用原生 API
这是一个功能最全的方案,但需要手动处理很多细节。它主要使用 Wlanapi.dll 中的函数,大致流程是打开句柄、枚举网卡、调用 WlanGetAvailableNetworkList 扫描网络并读取信号质量。
1. 核心结构体与函数定义
需要定义与 Windows API 交互所需的结构体和函数签名。
// 定义所需的结构体 (为简洁起见,此处略去详细字段定义,下同)
// 包括 WLAN_INTERFACE_INFO, WLAN_AVAILABLE_NETWORK 等,具体可参考开源项目
// 导入所需的 P/Invoke 方法
[DllImport("wlanapi.dll")]
public static extern int WlanOpenHandle(uint dwClientVersion, IntPtr pReserved, out uint pdwNegotiatedVersion, out IntPtr phClientHandle);
[DllImport("wlanapi.dll")]
public static extern int WlanEnumInterfaces(IntPtr hClientHandle, IntPtr pReserved, out IntPtr ppInterfaceList);
[DllImport("wlanapi.dll")]
public static extern int WlanGetAvailableNetworkList(IntPtr hClientHandle, ref Guid pInterfaceGuid, uint dwFlags, IntPtr pReserved, out IntPtr ppAvailableNetworkList);
// 其他方法如 WlanCloseHandle, WlanFreeMemory 等这种方式的完整实现较为复杂,主要的技术难点包括:正确申请和释放非托管内存 (Marshal.AllocHGlobal, Marshal.PtrToStructure) 以及精确匹配各种 API 版本,需要耗费大量精力调试。
方案二:使用社区封装的类库
这是更推荐的做法,能让我们专注于业务逻辑,而非复杂的 P/Invoke 和内存管理。下面推荐两个优秀的开源库。
1. 使用 Managed Wifi API
Managed Wifi API 是 Wlanapi.dll 的成熟 C# 封装,NuGet 包名为 NativeWifi,许多网络管理工具都用它开发。安装后需在代码文件头部引入 using NativeWifi;。
核心代码示例:列出所有网卡(Wifi 适配器),并打印每个网卡扫描到的无线网络。
using NativeWifi;
using System;
using System.Text;
public static void ListAllNetworks()
{
WlanClient client = new WlanClient();
foreach (WlanClient.WlanInterface wlanIface in client.Interfaces)
{
// 主动触发一次网络扫描,确保获取到最新的网络列表
wlanIface.Scan();
Console.WriteLine($"Wi-Fi 适配器: {wlanIface.InterfaceDescription}");
// 获取可用网络列表,参数 0 表示无特殊标志
Wlan.WlanAvailableNetwork[] networks = wlanIface.GetAvailableNetworkList(0);
foreach (Wlan.WlanAvailableNetwork network in networks)
{
string ssid = GetStringForSSID(network.dot11Ssid);
// wlanSignalQuality 范围是 0-100,值越大信号越强。
Console.WriteLine($" SSID: {ssid}, 信号质量: {network.wlanSignalQuality}%, 安全: {network.dot11DefaultCipherAlgorithm != 0}");
}
}
}
// 辅助方法:将 SSID 原始数据转换为字符串
static string GetStringForSSID(Wlan.Dot11Ssid ssid)
{
return Encoding.ASCII.GetString(ssid.SSID, 0, (int)ssid.SSIDLength);
}说明:WlanClient 和 WlanInterface 是核心类。网络是否安全的判断依据为:如果 dot11DefaultCipherAlgorithm 不为 0,则表示网络使用了某种加密算法。
2. 使用 SimpleWifi
SimpleWifi 是另一个极为轻量的库,它对 Managed Wifi API 做了更高层次的抽象,API 使用起来更简单。可以通过 NuGet 搜索 SimpleWifi 安装。安装后需引入 using SimpleWifi;。
核心代码示例:使用更现代的异步方法获取接入点并打印信号强度。
using SimpleWifi;
using System;
using System.Threading.Tasks;
public static async Task ListNetworksSimpleWifiAsync()
{
Wifi wifi = new Wifi();
if (wifi.NoWifiAvailable) // 判断系统是否有可用的 WiFi 网卡[reference:10]
{
Console.WriteLine("未检测到可用的Wi-Fi网卡。");
return;
}
// 异步获取所有接入点
var accessPoints = await wifi.GetAccessPointsAsync();
Console.WriteLine("扫描到的Wi-Fi网络列表:");
foreach (var ap in accessPoints)
{
// SignalStrength 是一个数值型属性,数值越大信号越好[reference:11]
Console.WriteLine($" SSID: {ap.Name}, 信号强度值: {ap.SignalStrength}, 是否需要密码: {ap.IsSecure}");
}
}到此这篇关于基于C#实现WiFi信号强度扫描的完整代码的文章就介绍到这了,更多相关C# WiFi信号强度扫描内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
