如何检查网络连接?

117

什么是确定网络连接是否可用的最佳方法?


4个回答

188

这个标记的答案完全没有问题,不过在某些情况下标准方法会被虚拟卡(虚拟盒子等)欺骗。而且通常有必要根据网络接口的速度(串行端口、调制解调器等)来丢弃一些网络接口。

以下是用于检查这些情况的代码:

    /// <summary>
    /// Indicates whether any network connection is available
    /// Filter connections below a specified speed, as well as virtual network cards.
    /// </summary>
    /// <returns>
    ///     <c>true</c> if a network connection is available; otherwise, <c>false</c>.
    /// </returns>
    public static bool IsNetworkAvailable()
    {
        return IsNetworkAvailable(0);
    }

    /// <summary>
    /// Indicates whether any network connection is available.
    /// Filter connections below a specified speed, as well as virtual network cards.
    /// </summary>
    /// <param name="minimumSpeed">The minimum speed required. Passing 0 will not filter connection using speed.</param>
    /// <returns>
    ///     <c>true</c> if a network connection is available; otherwise, <c>false</c>.
    /// </returns>
    public static bool IsNetworkAvailable(long minimumSpeed)
    {
        if (!NetworkInterface.GetIsNetworkAvailable())
            return false;

        foreach (NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces())
        {
            // discard because of standard reasons
            if ((ni.OperationalStatus != OperationalStatus.Up) ||
                (ni.NetworkInterfaceType == NetworkInterfaceType.Loopback) ||
                (ni.NetworkInterfaceType == NetworkInterfaceType.Tunnel))
                continue;

            // this allow to filter modems, serial, etc.
            // I use 10000000 as a minimum speed for most cases
            if (ni.Speed < minimumSpeed)
                continue;

            // discard virtual cards (virtual box, virtual pc, etc.)
            if ((ni.Description.IndexOf("virtual", StringComparison.OrdinalIgnoreCase) >= 0) ||
                (ni.Name.IndexOf("virtual", StringComparison.OrdinalIgnoreCase) >= 0))
                continue;

            // discard "Microsoft Loopback Adapter", it will not show as NetworkInterfaceType.Loopback but as Ethernet Card.
            if (ni.Description.Equals("Microsoft Loopback Adapter", StringComparison.OrdinalIgnoreCase))
                continue;

            return true;
        }
        return false;
    }

17
这是正确的,值得获得许多赞 - 我发现在被接受的答案中提到的NetworkAvailabilityChanged事件并不可靠地触发,这可能是由于此答案中提到的虚拟适配器所致。 - Marek
1
+1 对于虚拟机的额外检查。昨天遇到了这种情况。但我仍然认为这不能处理“Hype-V”,因为它们的名称中没有“virtual”。 - Herdo
3
@Herdo - 是的,这段代码并不完美,我认为在虚拟世界中是无法达到完美的。但你可以改进它。 - Simon Mourier
1
在我目前的项目中,我实施了一个周期性监控/轮询系统(使用简单的HTTP GET请求,因为我针对的是Web服务器),当检测到服务器处于“宕机”(无法通过HTTP访问)或“运行”(再次可访问)状态时会触发事件。通常情况下,您可以定义“可靠”的含义,并实现类似的逻辑。 - Simon Mourier
失败并出现“Microsoft Virtual Machine Bus Network Adapter”,该适配器在Win Server 2008上存在,我怀疑是使用Hyper-V或等效软件的VM主机或客户机。客户检测到问题,仅出现这两个隧道适配器和此适配器。 - tjmoore
显示剩余6条评论

159

您可以使用GetIsNetworkAvailable()在.NET 2.0中检查网络连接:

System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable()

要监控IP地址或网络可用性的变化,请使用NetworkChange类中的事件:

System.Net.NetworkInformation.NetworkChange.NetworkAvailabilityChanged
System.Net.NetworkInformation.NetworkChange.NetworkAddressChanged

9
这是否解决了“有限可用性”的问题? - tofutim
这在WPF中并不总是有效。有些笔记本电脑返回false,而有些则返回true。 - krilovich
这真的有效吗?我刚刚写了这一行代码,然后关闭了我的路由器,但它仍然返回 true! - Mushfiq
1
NetworkInterface.GetIsNetworkAvailable() 在我的应用程序中(.NET 4.5,Windows 10)非常不可靠,尤其是在虚拟机上运行时。从 NetworkAvailabilityChanged 处理事件一直是可靠的。 - eskimwier
这不是可靠的。阅读 https://dev59.com/jHI-5IYBdhLWcg3wED9V#25779403 - T.Todua
@T.Todua:你看到链接问题中的这个评论了吗?; “此代码仅检查网络电缆是否已插入。”在Windows下找到网络连接通常是困难的。 - Mitch Wheat

10

Microsoft Windows Vista和7使用NCSI(网络连接状态指示器)技术:

  1. NCSI对www.msftncsi.com进行DNS查找,然后请求http://www.msftncsi.com/ncsi.txt。该文件是一个纯文本文件,只包含文本'Microsoft NCSI'。
  2. NCSI发送DNS查找请求以获取dns.msftncsi.com。此DNS地址应解析为131.107.255.255。如果地址不匹配,则假定互联网连接未正常工作。

3
这很棒,但技术上并不是关于网络的可用性,而更多地是“我是否通过http拥有互联网连接?” 比如在独立的局域网中,你可以拥有完美的网络连接,但没有互联网连接。欲了解更多信息,请参阅NCSI:http://technet.microsoft.com/en-us/library/cc766017.aspx。 - MichielB

0
调用此方法以检查网络连接。
public static bool IsConnectedToInternet()
        {
            bool returnValue = false;
            try
            {

                int Desc;
                returnValue = Utility.InternetGetConnectedState(out Desc, 0);
            }
            catch
            {
                returnValue = false;
            }
            return returnValue;
        }

将此代码行以下的内容放置。
[DllImport("wininet.dll")]
        public extern static bool InternetGetConnectedState(out int Description, int ReservedValue);

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