如何在.net中获取可用的wifi接入点及其信号强度?

29
8个回答

19

这是一个使用C#编写的包装器项目,位于http://www.codeplex.com/managedwifi

它支持Windows Vista和XP SP2(或更高版本)。

示例代码:

using NativeWifi;
using System;
using System.Text;

namespace WifiExample
{
    class Program
    {
        /// <summary>
        /// Converts a 802.11 SSID to a string.
        /// </summary>
        static string GetStringForSSID(Wlan.Dot11Ssid ssid)
        {
            return Encoding.ASCII.GetString( ssid.SSID, 0, (int) ssid.SSIDLength );
        }

        static void Main( string[] args )
        {
            WlanClient client = new WlanClient();
            foreach ( WlanClient.WlanInterface wlanIface in client.Interfaces )
            {
                // Lists all networks with WEP security
                Wlan.WlanAvailableNetwork[] networks = wlanIface.GetAvailableNetworkList( 0 );
                foreach ( Wlan.WlanAvailableNetwork network in networks )
                {
                    if ( network.dot11DefaultCipherAlgorithm == Wlan.Dot11CipherAlgorithm.WEP )
                    {
                        Console.WriteLine( "Found WEP network with SSID {0}.", GetStringForSSID(network.dot11Ssid));
                    }
                }

                // Retrieves XML configurations of existing profiles.
                // This can assist you in constructing your own XML configuration
                // (that is, it will give you an example to follow).
                foreach ( Wlan.WlanProfileInfo profileInfo in wlanIface.GetProfiles() )
                {
                    string name = profileInfo.profileName; // this is typically the network's SSID

                    string xml = wlanIface.GetProfileXml( profileInfo.profileName );
                }

                // Connects to a known network with WEP security
                string profileName = "Cheesecake"; // this is also the SSID
                string mac = "52544131303235572D454137443638";
                string key = "hello";
                string profileXml = string.Format("<?xml version=\"1.0\"?><WLANProfile xmlns=\"http://www.microsoft.com/networking/WLAN/profile/v1\"><name>{0}</name><SSIDConfig><SSID><hex>{1}</hex><name>{0}</name></SSID></SSIDConfig><connectionType>ESS</connectionType><MSM><security><authEncryption><authentication>open</authentication><encryption>WEP</encryption><useOneX>false</useOneX></authEncryption><sharedKey><keyType>networkKey</keyType><protected>false</protected><keyMaterial>{2}</keyMaterial></sharedKey><keyIndex>0</keyIndex></security></MSM></WLANProfile>", profileName, mac, key);

                wlanIface.SetProfile( Wlan.WlanProfileFlags.AllUser, profileXml, true );
                wlanIface.Connect( Wlan.WlanConnectionMode.Profile, Wlan.Dot11BssType.Any, profileName );
            }
        }
    }
}

谢谢你提供的解决方案。但是对我并没有起作用。我正在使用Windows 8.1,而且我遇到了这个异常信息"An unhandled exception of type 'System.ComponentModel.Win32Exception' occurred in ManagedWifi.dll"。你有什么想法吗? - mr.b
我在我的一台机器上也遇到了这个错误,尽管我正在运行它在Windows 10和VS 2015上。有什么线索吗?你能解决它吗? - Apoorv

6

如果平台是Windows 10,则可以使用Microsoft.Windows.SDK.Contracts软件包访问所有可用的Wi-Fi。

首先,从NuGet安装Microsoft.Windows.SDK.Contracts软件包。

然后,您可以使用以下代码获取SSID和信号强度。

var adapters = await WiFiAdapter.FindAllAdaptersAsync();
foreach (var adapter in adapters)
{
    foreach (var network in adapter.NetworkReport.AvailableNetworks)
    {
        Console.WriteLine($"ssid: {network.Ssid}");
        Console.WriteLine($"signal strength: {network.SignalBars}");
    }
}

3

信号强度在Windows XP中无法使用,即使安装了所有SP也不行 :( - LDomagala

3
我正在使用C#代码运行命令netsh wlan show networks mode=bssid。"最初的回答"是指这个命令返回的原始结果。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace ConsoleApp2
{
    class AccessPoint
    {
        public string SSID { get; set; }
        public string BSSID { get; set; }
        public byte Signal { get; set; }
    }

    class Program
    {
        private static async Task Main(string[] args)
        {
            var apList = await GetSignalOfNetworks();

            foreach (var ap in apList)
            {
                WriteLine($"{ap.BSSID} - {ap.Signal} - {ap.SSID}");
            }

            Console.ReadKey();
        }

        private static async Task<AccessPoint[]> GetSignalOfNetworks()
        {
            string result = await ExecuteProcessAsync(@"C:\Windows\System32\netsh.exe", "wlan show networks mode=bssid");

            return Regex.Split(result, @"[^B]SSID \d+").Skip(1).SelectMany(network => GetAccessPointFromNetwork(network)).ToArray();
        }

        private static AccessPoint[] GetAccessPointFromNetwork(string network)
        {
            string withoutLineBreaks = Regex.Replace(network, @"[\r\n]+", " ").Trim();
            string ssid = Regex.Replace(withoutLineBreaks, @"^:\s+(\S+).*$", "$1").Trim();

            return Regex.Split(withoutLineBreaks, @"\s{4}BSSID \d+").Skip(1).Select(ap => GetAccessPoint(ssid, ap)).ToArray();
        }

        private static AccessPoint GetAccessPoint(string ssid, string ap)
        {
            string withoutLineBreaks = Regex.Replace(ap, @"[\r\n]+", " ").Trim();
            string bssid = Regex.Replace(withoutLineBreaks, @"^:\s+([a-f0-9]{2}(:[a-f0-9]{2}){5}).*$", "$1").Trim();
            byte signal = byte.Parse(Regex.Replace(withoutLineBreaks, @"^.*(Signal|Sinal)\s+:\s+(\d+)%.*$", "$2").Trim());

            return new AccessPoint
            {
                SSID = ssid,
                BSSID = bssid,
                Signal = signal,
            };
        }

        private static async Task<string> ExecuteProcessAsync(string cmd, string args = null)
        {
            var process = new Process()
            {
                StartInfo = new ProcessStartInfo
                {
                    FileName = cmd,
                    Arguments = args,
                    RedirectStandardInput = false,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    UseShellExecute = false,
                    CreateNoWindow = true,
                    StandardOutputEncoding = Encoding.UTF8,
                }
            };

            process.Start();

            string result = await process.StandardOutput.ReadToEndAsync();

            process.WaitForExit();

#if DEBUG
            if (result.Trim().Contains("The Wireless AutoConfig Service (wlansvc) is not running."))
            {
                return await GetFakeData();
            }
#endif

            return result;
        }

        private static async Task<string> GetFakeData()
        {
            var assembly = Assembly.GetExecutingAssembly();
            var resourceName = "ConsoleApp2.FakeData.txt";

            using (Stream stream = assembly.GetManifestResourceStream(resourceName))
            using (StreamReader reader = new StreamReader(stream))
            {
                return await reader.ReadToEndAsync();
            }
        }

        private static void WriteLine(string str)
        {
            Console.WriteLine(str);
        }
    }
}

0

你也许可以使用WMI查询来实现它。看一下这个thread


虽然 WMI MSNdis_80211_BSSIList 的描述中说在填充任何内容之前需要进行一次调查,但实际上这似乎是可行的。不知道如何进行调查。 - undefined

0

如果您正在使用Vista,WMI可能无法与所有网络适配器一起使用。对于Vista的另一种选择是使用netsh命令。请参阅this codeproject article.


1
谢谢提供链接。使用netsh的问题在于它不能给我所有需要的信息(如rssi),有时也会出现一些错误。 - LDomagala

0

我发现其他答案非常有用,想看看它们彼此之间的比较。这里是一些LINQ代码,可以从每个数据源获取数据并将它们连接起来。这里有一个LINQPad脚本,其中包含所有NuGet依赖项和使用方法:http://share.linqpad.net/7pxls3.linq

var adapters = await WiFiAdapter.FindAllAdaptersAsync();

var wifiAdapterResults = adapters
.SelectMany(a => a.NetworkReport.AvailableNetworks.Select(a => new
{
    a.Ssid,
    a.Bssid,
    Ghz = Math.Round(a.ChannelCenterFrequencyInKilohertz / 1000000.0, 1),
    a.NetworkRssiInDecibelMilliwatts,
    a.SignalBars,
    a.PhyKind,
}))
.Where(n => n.Ssid != null)
.OrderByDescending(n => n.NetworkRssiInDecibelMilliwatts);

WlanClient client = new WlanClient();

var wlanResults = client.Interfaces.SelectMany(i => i.GetNetworkBssList().Select(n => new
{
    SSID = new string(Encoding.ASCII.GetChars(n.dot11Ssid.SSID, 0, (int)n.dot11Ssid.SSIDLength)),
    n.linkQuality,
    n.rssi,
    MAC = BitConverter.ToString(n.dot11Bssid).Replace('-', ':').ToLowerInvariant(),
}))
.OrderByDescending(n => n.rssi);

wifiAdapterResults.Join(wlanResults, r => r.Bssid, r => r.MAC, (r1, r2) => Util.Merge(r1, r2)).Dump();

Util.Merge函数是LINQPad的概念,如果你想在LINQPad之外运行,你必须自己创建合并的对象。

内置的WinRT WifiAdapter 更容易调用,但没有一个好的链接质量值,只有非常粒度化的SignalBars和rssi。另一方面,ManagedWifi库有一个1-100的linkQuality值,似乎更有用。

希望其他人也会发现这个有用!


-3

我找到了另一种方法来解决这个问题,不过需要花费一些钱。

rawether.net有一个.NET库可用,可以让你获取以太网驱动程序。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接