如何在C#中检测网络连接是否正常工作?

29

我有一段C#代码,基本上使用 FtpWebRequest 协议上传文件。然而,我想首先确定是否存在可用的互联网连接,然后再尝试上传文件(因为如果没有可用互联网连接,尝试上传文件是毫无意义的,软件应该只需等待一段时间并再次检查)。

是否有简单的方法来实现这个功能?还是应该先尝试上传文件,如果失败了就再次尝试,假设网络连接已经中断?


1
大家好!首先,感谢你们的回答!我会选择JaredPar的优雅答案。@Damien:我知道很多事情可能发生,我只想做一个简单的事情:有网络连接吗?没有?30分钟后再回来。是的?好的,让我们尝试上传。采用JaredPar的代码应该不难。没有更复杂的东西了。还是谢谢你的回答。@kzen:Ping不是一个很好的答案。就我而言,在我的公司中,ICMP请求被阻止了,所以即使有工作连接,通过这种方式检查也会失败。无论如何,还是谢谢! - Detariael
Andy Shellam:你的回答基本上与JaredPar的相同,我没有选择它,只是因为我觉得JaredPar的看起来更优雅。无论如何,感谢你的回答! - Detariael
将接受的答案切换为Zyo的答案,因为它包括回环/隧道。 - Detariael
首先找到任意网络卡的IP地址。其次,使用此链接:https://dev59.com/hFDTa4cB1Zd3GeqPI2dK - Hady Mahmoodi
使用此页面输入链接说明 - Hady Mahmoodi
7个回答

33

只需使用原始函数即可

System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable()

返回true或false以指示连接是否正常。

来自MSDN: 如果任何网络接口被标记为“up”且不是回环或隧道接口,则视为可用的网络连接。

请注意,仅检查联通性还不够,例如您可能已连接到本地网络,但路由器未连接Internet。要确切知道是否连接到互联网,请尝试使用Ping类。


断开电缆时,上述方法返回TRUE。 - mmmmmm
@mmmmmm 断开电缆并不意味着所有网络都无法使用。例如,您可能正在使用WiFi。 - Zyo
如果您想确定用户是否连接到互联网,Ping类似乎是最好的选择。 - The Muffin Man

15

存在一个"网络可用性更改"事件,当非隧道或回环接口上的网络连接状态从"断开"变为"连接"时触发。

您可以在启动时读取系统上所有网络适配器的状态,存储"网络可用性"的当前值,然后监听此事件,并在此事件触发时更改网络状态变量。这看起来也将处理拨号和ISDN连接。

当然,还有其他因素需要考虑,例如NIC连接到路由器(并且工作),但路由器上的Internet连接已断开或远程主机未响应,但这将至少防止您尝试建立不可能工作的连接(例如VPN或ISDN链接处于断开状态)。

这是一个C#控制台应用程序-启动它,然后禁用或拔掉您的网络连接 :-)

class Program
{
    static bool networkIsAvailable = false;

    static void Main(string[] args)
    {
        NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();

        foreach (NetworkInterface nic in nics)
        {
            if (
                (nic.NetworkInterfaceType != NetworkInterfaceType.Loopback && nic.NetworkInterfaceType != NetworkInterfaceType.Tunnel) &&
                nic.OperationalStatus == OperationalStatus.Up)
            {
                networkIsAvailable = true;
            }
        }

        Console.Write("Network availability: ");
        Console.WriteLine(networkIsAvailable);

        NetworkChange.NetworkAvailabilityChanged += new NetworkAvailabilityChangedEventHandler(NetworkChange_NetworkAvailabilityChanged);

        Console.ReadLine();
    }

    static void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
    {
        networkIsAvailable = e.IsAvailable;

        Console.Write("Network availability: ");
        Console.WriteLine(networkIsAvailable);
    }
}

1
+1 意味着意识到环回和隧道并不代表连接。但愿在尝试实现已接受的答案之前我能读到你的回答... - colithium

12

我认为你可以使用的最佳近似值是检查NetworkInterface类型上的OperationalStatus值。

using System.Net.NetworkInformation;

public bool IsNetworkLikelyAvailable() {
  return NetworkInterface
    .GetAllNetworkInterfaces()
    .Any(x => x.OperationalStatus == OperationalStatus.Up);
}

请记住,这只是一个近似值。当此方法返回时,计算机可能会失去或获得网络连接。我认为最好直接上传并处理错误,因为你无法证明这不会发生。


1
这可能会返回环回接口和您设置的任何隧道接口。即使其中任何一个报告“Up”,您也应该报告“no”。我知道环回几乎总是报告“Up”,而不管互联网状态如何。 - colithium
谢谢你的帮助,JaredPar。你让我的应用程序设计变得更加容易了。 - grefly

6
考虑这样一种情况,当你的检查显示“连接已建立”时,你还没开始FTP,连接就断开了。或者在FTP请求中途连接断开。鉴于无论如何都必须为这些情况编写代码,因此可以跳过检查。你也可能遇到相反的情况-当你检查连接时,没有连接存在,但是稍后他们的连接出现了。那么现在该怎么办呢?即使现在连接可用,你是否会开始不断地提醒用户连接不存在?总之,你正在处理大量资源(你的网络连接、任何中间路由器、主机及其FTP服务)。所有这些都可能在你的控制范围之外发生变化(如Seth的评论所示),而没有任何预测试将回答“我能完成这次上传吗?”的问题。正如OP指出的,他正在考虑“稍后重试”的方法,因此我认为应该在后台执行所有操作,不会干扰用户-除非你尝试了“不合理”的时间仍然没有成功。

+1 一个工作的网络连接并不意味着远程主机正常并且有一个可用的FTP服务器。 - Seth
5
不错的回答,但我认为你可能反其道而行:如果没有连接,你的程序不应尝试发起任何通信 - 否则你可能会发现它在超时时被锁定,或者浪费CPU时间在徒劳无功的尝试上,或者向用户报告数百个愚蠢的错误。好的程序将优雅地检测到链接已离线并停止尝试使用它。 - Jason Williams

6

2
除非远程主机阻止ping请求,否则这将失败- 这是一种良好的做法,一些大型托管提供商确实这样做。 - Andy Shellam
是的,我认为这很明显,所以我没有提及它...正如其他人已经注意到的那样,在任何检查的情况下,无法绝对确定连接在FTP请求的确切时间可用,但我觉得ping是一个足够好的近似值,并且非常容易实现。 - Dean Kuga

5
如果使用ping工具很困难,您可以使用WebClient。
public static bool CheckForInternetConnection()
{
   try
   {
       using (var client = new WebClient())
       using (var stream = client.OpenRead("http://www.google.com"))
       {
          return true;
       }
   }
   catch
   {
       return false;
   }
}

或者任何其他网站。 编辑:你可以使用http://www.msftncsi.com/这个网站。 这是一个仅用于互联网连接的网站。请参阅详细的注册表说明,了解Windows 7如何查找互联网连接:http://blog.superuser.com/2011/05/16/windows-7-network-awareness/


2

我刚刚编写了异步函数来完成这个任务:

    private void myPingCompletedCallback(object sender, PingCompletedEventArgs e)
    {
        if (e.Cancelled)
            return;

        if (e.Error != null)
            return;

        if (e.Reply.Status == IPStatus.Success)
        {
            //ok connected to internet, do something...
        }
    }

    private void checkInternet()
    {
        Ping myPing = new Ping();
        myPing.PingCompleted += new PingCompletedEventHandler(myPingCompletedCallback);
        try
        {
            myPing.SendAsync("google.com", 3000 /*3 secs timeout*/, new byte[32], new PingOptions(64, true));
        }
        catch
        {
        }
    }

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