determining the current link speed of WiFi in C#
Asked Answered
R

3

5

I am writing a program that does one thing, it finds out the current link speed of the wifi connection and reports it to the user in real time. the problem I am having is that it does not seem to be able to find out the current link speed, only the max link speed of the device (300 Mbps). the reason I am writing this is that I have a problem where, periodically the link speed will drop drastically (down to 1-2 Mbps) and I want to be able to see when that happens. with this code it will simply give me the maximum speed that the adapter supports, not the current link speed of the connection.

private void update(object state)
{

    System.Net.NetworkInformation.NetworkInterface[] nics = null;
    nics = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces();
    long speed = 0;
    string adapter = "";
    foreach (System.Net.NetworkInformation.NetworkInterface net in nics)
    {
        if (net.Name.Contains("Wireless") || net.Name.Contains("WiFi") || net.Name.Contains("802.11") || net.Name.Contains("Wi-Fi"))
        {
            speed = net.Speed;
            adapter = net.Name;
            break;
        }
    }
    string temp;
    if (speed == 0)
    {
        temp = "There is currently no Wi-Fi connection";
    }
    else
    {
        temp = "Current Wi-Fi Speed: " + (speed / 1000000) + "Mbps on " + adapter;
    }
    if (label1.InvokeRequired)
    {
        SetTextCallback d = new SetTextCallback(update);
        label1.Invoke(d, new object[] { temp });
    }
    else
    {
        label1.Text = temp;
    }
}

this run by calling

System.Threading.Timer ticker = new System.Threading.Timer(update, label1, 0, 1000);

in the main method.

Retentivity answered 7/7, 2013 at 21:26 Comment(0)
S
16

Since this took roughly a day of research, I've outlined what I attempted which (hopefully) will be helpful for future reference—namely what did and didn't work to answer this question.

tl;dr: Scroll to the The Code section

What I found

Good ol' control panel

If you are looking for the really easy way to do this you can simply go and open Contol Panel. Depending on what version of Windows you are on (in my case I'm on Windows 8), the path to the page is Control Panel >> Network and Internet >> Network and Sharing Center and then you can click on the link next to "Connections: " which will give you a window that looks like what is below.Wi-Fi Info Window
The current link speed is highlighted in red which in my case is 36.0 Mbps. Though, of course, this might not satisfy your original question if you were intending to integrate some code with the actual value.

WMI

With a mix of Googling and whatnot, I thought I might have found something in Windows Management Instrumentation.

Long story short, AFAIK, WMI does not have what we're looking for.

WMI, in short, is a giant object database (that can also be queried through SQL) that allows you to query information about a Windows machine such as process, disks, etc. In WMI, everything is represented by a class with a series of instances each with a set of properties.
Anyhow, WMI Explorer allows you to view all of this on your machine.

I (supposedly) found two classes on MSDN that might have the info on link speed but from WMI Explorer, there was nothing useful.

The first class, MSFT_NetAdapter, did not even show up in WMI Explorer on my machine.

The second class, Win32_NetworkAdapter, showed up in WMI Explorer, but the Speed property was still incorrect. The same network adapter was showing a value of 168000000 or 168 Mbps which is not right. Though I find this strange because there was already a MaxSpeed but it was blank.

Scratch WMI off the list.

Win32 P/Invoke

Yes, of course, the solution to everything is always calling unmanaged Win32 APIs using P/Invoke magic.

This is the route used to solve the problem.

Luckily, the IP_ADAPTER_ADDRESSES structure solves the problem. If you look at the MSDN page, it's a fairly large structure but what is important here is TransmitLinkSpeed which actually works.

Calling the GetAdaptersAddresses() function will return the actual structure.

Now, the actual C# P/Invoke code. Luckily, pinvoke.net already had interop for this function which I've added. This is all that was necessary.

The Code

Finally, here is your code patched up with the new P/Invoke black magic. I've made it work as a console application for demo purposes:

Using Statements:

using System;
using System.Threading;

Code:

class Program
{
    private static void Main(string[] args)
    {
        Timer ticker = new Timer(Update, null, 0, 1000);

        // Keep the main thread from dying
        while (true)
        {
            Thread.Sleep(1000);
        }
    }

    private static void Update(object state)
    {
        ulong speed = 0;
        string adapter = "";

        string[] nameSearches = { "Wireless", "WiFi", "802.11", "Wi-Fi" };

        // The enum value of `AF_INET` will select only IPv4 adapters.
        // You can change this to `AF_INET6` for IPv6 likewise
        // And `AF_UNSPEC` for either one
        foreach (IPIntertop.IP_ADAPTER_ADDRESSES net in IPIntertop.GetIPAdapters(IPIntertop.FAMILY.AF_INET))
        {
            bool containsName = false;
            foreach (string name in nameSearches)
            {
                if (net.FriendlyName.Contains(name))
                {
                    containsName = true;
                }
            }
            if (!containsName) continue;

            speed = net.TrasmitLinkSpeed;
            adapter = net.FriendlyName;
            break;
        }
        
        string temp;
        if (speed == 0)
        {
            temp = "There is currently no Wi-Fi connection";
        }
        else
        {
            temp = string.Format("Current Wi-Fi Speed: {0} Mbps on {1}", (speed / 1000000.0), adapter);
        }
        
        Console.WriteLine(temp);
    }
}

You are then going to be looking for the actual IPIntertop class that I updated. Since it's pretty big you can find it updated at pinvoke.net or on this PasteBin in case something goes down.

Bottom Line

Windows has a lot of APIs which are somewhat broken (WMI), can have a few "leaky abstractions" (.Net), or can be a pain to work with (Win32).

Sigh, that is a lot and I hope it helps.

Ship answered 7/7, 2013 at 21:42 Comment(3)
im not trying to determine the internet speed, I am trying to determine the link speed of the 802.11n connection. these would be numbers like 28, 56, 72, 96, 116, 124, 130, 148, 156, 162, 192, 216, 232, 240, 270 or 300. This is information that I can get without even being connected to the internet. it is the theoretical max bandwidth that can be sent over the network, not the actual max.Retentivity
thank you very much for this. I already had the control panel method, as well as another method that is windows 8 specific but none of those fit what I needed. your code is exactly what I was looking for so thank you very much for that.Retentivity
Anybody tested this on uwp?Thunderhead
D
1

I come accross the same issue, and need to get windows wifi link speed which is current negotiated. and thanks to @Jaxrtech's WMI approach, that really works. the correct class is CIM_NetworkAdapter(i'm using windows7), and query the speed column to get the current speed. while wifi current negotiated speed is changing, this speed is changing too. i tested it, this matched ok.

select Description , DeviceID, Speed from CIM_NetworkAdapter

get:

D-Link DWA-140 RangeBooster N USB Adapter    17    285000000
Dulcedulcea answered 23/7, 2013 at 8:52 Comment(0)
U
1

Since no-one here mentioned it yet: why not use https://learn.microsoft.com/en-us/dotnet/api/system.net.networkinformation.networkinterface.speed?view=net-5.0#System_Net_NetworkInformation_NetworkInterface_Speed

This is, if the table on this site is correct included since .NET Framework 2.0 and seem to included in all other versions of .net including .net core.

Urban answered 30/6, 2021 at 13:22 Comment(1)
this shows maximum speed of the adapter and not current download/upload speed. Correct me if i am wrong pleaseReinold

© 2022 - 2024 — McMap. All rights reserved.