使用.NET检查Internet连接的最佳方法是什么?

Moh*_*nde 224 .net c# internet-connection

在.NET中检查Internet连接的最快,最有效的方法是什么?

Cha*_*ion 271

这样的事情应该有效.

System.Net.WebClient

public static bool CheckForInternetConnection()
{
    try
    {
        using (var client = new WebClient())
            using (client.OpenRead("http://google.com/generate_204")) 
                return true; 
    }
    catch
    {
        return false;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @dbasnett在某个地方,我读了一份报告,76%的统计数据是当场弥补的. (24认同)
  • 这可能比ping谷歌更好,因为我认为我们无法保证Google会继续响应ping.另一方面,我无法想象一个www.google.com不会返回某些HTML的世界:) (14认同)
  • 这实际上并不那么有效.使用它可以让我的程序在没有互联网的情况下开始超过1分钟.可能是由于尝试解析DNS.Ping 8.8.8.8(谷歌dns)将其更改为3秒. (14认同)
  • 无论哪种方式,没有理由将4KB拉回来 - 只需使用client.OpenRead(url).如果它没有抛出异常,那么就可以连接了. (9认同)
  • @DanielVassallo`我无法想象一个www.google.com在中国没有返回某些HTML的世界......例如...... (5认同)
  • @Daniel:一方面是真的,但另一方面,实际下载网站有点开销 (3认同)
  • 将 using 语句替换为 `using (var client = new WebClient() { Proxy = null })` 使其在我的计算机上更快;) (3认同)
  • 谷歌被封锁了吗? (3认同)
  • 如果您正在测试Internet连接以便可以连接到特定站点(例如应用程序服务器),那么您应该将HTTP请求发送到该站点,而不是Google.是的,即将离任的PING被一些学校和企业封锁,所以这不是一个可靠的方法. (3认同)
  • 您可以通过添加更多 URL(如 www.facebook.com 和 www.twitter.com)使此方法更加可靠,这三个都失败的可能性为零。 (2认同)
  • 与 System.Net.Sockets.TcpClient 相比,这有什么好处?我的意思是 WebClient 方法需要几秒钟,而 TcpClient 需要 < 200 毫秒。System.Net.Sockets.TcpClient 客户端 = new System.Net.Sockets.TcpClient("www.google.com", 80); (2认同)

Leo*_*Leo 77

绝对没有办法可以可靠地检查是否有互联网连接(我认为你的意思是访问互联网).

但是,您可以请求几乎从不离线的资源,例如ping google.com或类似的东西.我认为这会很有效率.

try { 
    Ping myPing = new Ping();
    String host = "google.com";
    byte[] buffer = new byte[32];
    int timeout = 1000;
    PingOptions pingOptions = new PingOptions();
    PingReply reply = myPing.Send(host, timeout, buffer, pingOptions);
    return (reply.Status == IPStatus.Success);
}
catch (Exception) {
    return false;
}
Run Code Online (Sandbox Code Playgroud)

  • +1"绝对没有办法可以可靠地检查是否有互联网连接" (24认同)
  • 这与我的答案的主要陈述有何矛盾? (12认同)
  • 使用"google.com"会花费更多时间,因为需要解决.相反,直接使用IP进行ping操作会更快.Ping到Google Public DNS IP地址(`8.8.8.8`或`8.8.4.4`)对我来说很好. (10认同)
  • 我想重申一点:"当心 - 许多学校和办公室阻止了ping协议.如果你将这种方法用于客户端使用的应用程序,我建议不要使用这种检查互联网的方法 (8认同)
  • 所有这一切都是检查谷歌是否已经启动了.如果在你成功ping之后的下一个瞬间,互联网会下降,那么呢?在做之前没有必要检查. (5认同)

dba*_*ett 40

而不是检查,只需执行操作(Web请求,邮件,ftp等),并为失败请求做好准备,即使您的检查成功,您也必须这样做.

考虑以下:

1 - check, and it is OK
2 - start to perform action 
3 - network goes down
4 - action fails
5 - lot of good your check did
Run Code Online (Sandbox Code Playgroud)

如果网络中断,您的操作将像ping一样快速失败等.

1 - start to perform action
2 - if the net is down(or goes down) the action will fail
Run Code Online (Sandbox Code Playgroud)

  • 对!做到这一点 - 但要为所有结果做好准备. (7认同)
  • 请考虑以下事项:如果网络停机x次,则需要_Do Something_(例如,tracelog,路由器重置) (2认同)
  • 不是OP,但我想这样做的原因是如果互联网连接不可用,请避免默认100秒超时.HTTP请求在后台线程上完成,因此UI线程没有被阻止,但是我的应用程序无法退出,直到后台线程从HTTP请求返回并终止.如果我知道互联网连接断开,我想完全避免这个请求,而不是试图找到一些"快乐的中等"超时值. (2认同)
  • 我的观点是,我们无法解释远程服务何时可用/不可用.那么,那些不响应ping的站点呢? (2认同)
  • 另一个用例是在线检查器,一旦我的互联网恢复,它就会提醒我 (2认同)

Kam*_*hid 28

NetworkInterface.GetIsNetworkAvailable非常不可靠.只是有一些VMware或其他LAN连接,它将返回错误的结果.另外关于Dns.GetHostEntry方法我只关心测试URL是否可能在我的应用程序要部署的环境中被阻止.

所以我发现的另一种方法是使用InternetGetConnectedState方法.我的代码是

[System.Runtime.InteropServices.DllImport("wininet.dll")]
private extern static bool InternetGetConnectedState(out int Description, int ReservedValue);

public static bool CheckNet()
{
     int desc;
     return InternetGetConnectedState(out desc, 0);         
}
Run Code Online (Sandbox Code Playgroud)

  • 直到现在,这对我来说非常适合. (5认同)
  • 此代码仅检查网络电缆是否已插入. (3认同)
  • 对我来说最好的方法,我仍然检查我的服务连接,然后启动例程...我只是想避免异常. (2认同)
  • 此代码不可移植到 Linux、MacOS。 (2认同)

小智 13

通过ping Google来测试互联网连接:

new Ping().Send("www.google.com.mx").Status == IPStatus.Success
Run Code Online (Sandbox Code Playgroud)

  • 当心 - 许多学校和办公室阻止ping协议.傻,我知道. (13认同)
  • 与此问题的原始作者相比,对此答案的描述将对更多人有益. (7认同)

PJR*_*bot 11

我不同意那些表示:"在执行任务之前检查连接的重点是什么,因为检查后连接可能会丢失".当然,我们作为开发人员所承担的许多编程任务存在一定程度的不确定性,但将不确定性降低到接受程度是挑战的一部分.

我最近遇到了这个问题,制作了一个包含链接到在线磁贴服务器的映射功能的应用程序.在注意到缺乏互联网连接的情况下,将禁用此功能.

此页面上的一些响应非常好,但是确实导致很多性能问题,例如挂起,主要是在没有连接的情况下.

以下是我最终使用的解决方案,借助其中一些答案和我的同事:

         // Insert this where check is required, in my case program start
         ThreadPool.QueueUserWorkItem(CheckInternetConnectivity);
    }

    void CheckInternetConnectivity(object state)
    {
        if (System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
        {
            using (WebClient webClient = new WebClient())
            {
                webClient.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.BypassCache);
                webClient.Proxy = null;
                webClient.OpenReadCompleted += webClient_OpenReadCompleted;
                webClient.OpenReadAsync(new Uri("<url of choice here>"));
            }
        }
    }

    volatile bool internetAvailable = false; // boolean used elsewhere in code

    void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
    {
        if (e.Error == null)
        {
            internetAvailable = true;
            Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() =>
            {
                // UI changes made here
            }));
        }
    }
Run Code Online (Sandbox Code Playgroud)


Jin*_*lye 10

Ping google.com 引入了 DNS 解析依赖项。Ping 8.8.8.8 很好,但 Google 离我很远。我需要做的就是 ping 互联网上离我最近的东西。

我可以使用 Ping 的 TTL 功能来 ping 跳 #1,然后跳 #2,等等,直到我收到来自可路由地址上的某些内容的回复;如果该节点位于可路由地址上,则它位于 Internet 上。对于我们大多数人来说,第 1 跳将是我们的本地网关/路由器,第 2 跳将是光纤连接另一端的第一个点或其他任何地方。

这段代码对我有用,并且比该线程中的其他一些建议响应更快,因为它正在 ping 互联网上离我最近的任何东西。


using System.Diagnostics;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Threading.Tasks;
    
public static async Task<bool> IsConnectedToInternetAsync()
{
    const int maxHops = 30;
    const string someFarAwayIpAddress = "8.8.8.8";
    
    // Keep pinging further along the line from here to google 
    // until we find a response that is from a routable address
    for (int ttl = 1; ttl <= maxHops; ttl++)
    {
        var options = new PingOptions(ttl, true);
        byte[] buffer = new byte[32];
        PingReply reply;
        try
        {
            using (var pinger = new Ping())
            {
                reply = await pinger.SendPingAsync(someFarAwayIpAddress, 10000, buffer, options);
            }
        }
        catch (PingException pingex)
        {
            Debug.Print($"Ping exception (probably due to no network connection or recent change in network conditions), hence not connected to internet. Message: {pingex.Message}");
            return false;
        }
    
        string address = reply.Address?.ToString() ?? null;
        Debug.Print($"Hop #{ttl} is {address}, {reply.Status}");
    
        if (reply.Status != IPStatus.TtlExpired && reply.Status != IPStatus.Success)
        {
            Debug.Print($"Hop #{ttl} is {reply.Status}, hence we are not connected.");
            return false;
        }
    
        if (isRoutableAddress(reply.Address))
        {
            Debug.Print("That's routable, so we must be connected to the internet.");
            return true;
        }
    }
    
    return false;
}
    
private static bool IsRoutableAddress(IPAddress addr)
{
    if (addr == null)
    {
        return false;
    }
    else if (addr.AddressFamily == AddressFamily.InterNetworkV6)
    {
        return !addr.IsIPv6LinkLocal && !addr.IsIPv6SiteLocal;
    }
    else // IPv4
    {
        byte[] bytes = addr.GetAddressBytes();
        if (bytes[0] == 10)
        {   // Class A network
            return false;
        }
        else if (bytes[0] == 172 && bytes[1] >= 16 && bytes[1] <= 31)
        {   // Class B network
            return false;
        }
        else if (bytes[0] == 192 && bytes[1] == 168)
        {   // Class C network
            return false;
        }
        else
        {   // None of the above, so must be routable
            return true;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Hac*_*Man 10

我已经看到上面列出的所有选项,唯一可行的选项来检查互联网是否可用是"Ping"选项.导入 [DllImport("Wininet.dll")]和/ System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces()NetworkInterface 该类的任何其他变体 在检测网络的可用性时不能很好地工作.这些方法仅检查网络电缆是否插入.

"Ping选项"

if(连接可用)返回 true

if(连接不可用且插入网络电缆)返回 false

if(未插入网络电缆) Throws an exception

NetworkInterface

if(互联网可用)退货 True

if(Internet不可用并且已插入网络电缆)返回 True

if(未插入网络电缆)返回 false

[DllImport("Wininet.dll")]

if(互联网可用)退货 True

if(Internet不可用并且已插入网络电缆)返回 True

if(未插入网络电缆)返回 false

因此,如果[DllImport("Wininet.dll")]NetworkInterface 无法知道互联网连接是否可用.


小智 8

没有解决在检查和运行代码之间网络崩溃的问题,但是相当可靠

public static bool IsAvailableNetworkActive()
{
    // only recognizes changes related to Internet adapters
    if (System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
    {
        // however, this will include all adapters -- filter by opstatus and activity
        NetworkInterface[] interfaces = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces();
        return (from face in interfaces
                where face.OperationalStatus == OperationalStatus.Up
                where (face.NetworkInterfaceType != NetworkInterfaceType.Tunnel) && (face.NetworkInterfaceType != NetworkInterfaceType.Loopback)
                select face.GetIPv4Statistics()).Any(statistics => (statistics.BytesReceived > 0) && (statistics.BytesSent > 0));
    }

    return false;
}
Run Code Online (Sandbox Code Playgroud)


bre*_*eez 5

下面是它在 Android 中的实现方式。

作为概念证明,我将此代码翻译为 C#:

var request = (HttpWebRequest)WebRequest.Create("http://g.cn/generate_204");
request.UserAgent = "Android";
request.KeepAlive = false;
request.Timeout = 1500;

using (var response = (HttpWebResponse)request.GetResponse())
{
    if (response.ContentLength == 0 && response.StatusCode == HttpStatusCode.NoContent)
    {
        //Connection to internet available
    }
    else
    {
        //Connection to internet not available
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 5

介绍

在某些情况下,您需要在 Windows 应用程序中使用 C# 代码检查互联网是否可用。可能是在 Windows 窗体中使用互联网下载或上传文件,或者从远程位置的数据库获取一些数据,在这些情况下,必须进行互联网检查。

有一些方法可以使用 C# 从代码隐藏中检查互联网可用性。这里解释了所有这些方法,包括它们的局限性。

  1. InternetGetConnectedState(wininet)

'wininet' API 可用于检查本地系统是否具有活动的互联网连接。用于此目的的命名空间是“System.Runtime.InteropServices”,并使用 DllImport 导入 dll“wininet.dll”。之后,创建一个带有 extern static 的布尔变量,其函数名称为 InternetGetConnectedState,并带有两个参数 description 和 returnedValue,如示例中所示。

注意:extern 修饰符用于声明外部实现的方法。当您使用 Interop 服务调用非托管代码时,extern 修饰符的常见用途是与 DllImport 属性一起使用。在这种情况下,该方法也必须声明为静态的。

接下来创建一个名为“IsInternetAvailable”作为布尔值的方法。该方法将使用上述函数返回本地系统的互联网状态

[DllImport("wininet.dll")]
private extern static bool InternetGetConnectedState(out int description, int reservedValue);
public static bool IsInternetAvailable()
{
    try
    {
        int description;
        return InternetGetConnectedState(out description, 0);
    }
    catch (Exception ex)
    {
        return false;
    }
}
Run Code Online (Sandbox Code Playgroud)
  1. 获取网络是否可用

以下示例使用 GetIsNetworkAvailable 方法来确定网络连接是否可用。

if (System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
{
    System.Windows.MessageBox.Show("This computer is connected to the internet");
}
else
{
    System.Windows.MessageBox.Show("This computer is not connected to the internet");
}
Run Code Online (Sandbox Code Playgroud)

备注(根据 MSDN):如果任何网络接口标记为“启动”并且不是环回或隧道接口,则认为网络连接可用。

在许多情况下,设备或计算机未连接到有用的网络,但仍被视为可用,并且 GetIsNetworkAvailable 将返回 true。例如,如果运行应用程序的设备连接到需要代理的无线网络,但未设置代理,则 GetIsNetworkAvailable 将返回 true。GetIsNetworkAvailable 返回 true 的另一个示例是,如果应用程序正在连接到集线器或路由器的计算机上运行,​​而集线器或路由器已丢失上游连接。

  1. Ping 网络上的主机名

Ping 和 PingReply 类允许应用程序通过从主机获取回复来确定是否可以通过网络访问远程计算机。这些类在 System.Net.NetworkInformation 命名空间中可用。以下示例显示如何 ping 主机。

protected bool CheckConnectivity(string ipAddress)
{
    bool connectionExists = false;
    try
    {
        System.Net.NetworkInformation.Ping pingSender = new System.Net.NetworkInformation.Ping();
        System.Net.NetworkInformation.PingOptions options = new System.Net.NetworkInformation.PingOptions();
        options.DontFragment = true;
        if (!string.IsNullOrEmpty(ipAddress))
        {
            System.Net.NetworkInformation.PingReply reply = pingSender.Send(ipAddress);
            connectionExists = reply.Status == 
System.Net.NetworkInformation.IPStatus.Success ? true : false;
        }
    }
    catch (PingException ex)
    {
        Logger.LogException(ex.Message, ex);
    }
    return connectionExists;
}
Run Code Online (Sandbox Code Playgroud)

备注(根据 MSDN):应用程序使用 Ping 类来检测远程计算机是否可访问。网络拓扑可以决定 Ping 是否可以成功联系远程主机。代理、网络地址转换 (NAT) 设备或防火墙的存在和配置可能会阻止 Ping 成功。Ping 成功仅表明网络上可以到达远程主机;不保证远程主机上存在更高级别的服务(例如 Web 服务器)。

欢迎提出意见/建议。快乐编码......!