繁体   English   中英

C# 如何检测互联网连接/断开连接(带有事件)?

[英]C# How to detect internet connection / disconnection (with an event)?

我写了这段完美运行的代码,但我担心每 2 秒 ping 一次会消耗太多资源,或者会导致互联网连接出现一些问题。

        new Thread(() =>
        {
            if (CheckInternetConnection() == false)
            {
                Dispatcher.Invoke(new Action(delegate
                {
                    //internet access lost
                }));
            }
            else
            {
                Dispatcher.Invoke(new Action(delegate
                {
                    //internet access
                }));
            }

            Thread.Sleep(2000);
        }).Start();
    [DllImport("wininet.dll")]
    private extern static bool InternetGetConnectedState(out int Description, int ReservedValue);
    public static bool CheckInternetConnection()
    {
        int output = 0;
        return InternetGetConnectedState(out output, 0);
    }

这两个事件并非在所有情况下都起作用(仅当IP或网卡发生变化时)

NetworkChange.NetworkAvailabilityChanged += NetworkChange_NetworkAvailabilityChanged
NetworkChange.NetworkAddressChanged += NetworkChange_NetworkAddressChanged;

有人可以帮助我吗?

注意:关于您原来的解决方案

NetworkChange.NetworkAvailabilityChanged工作正常,但有几个警告:1) 它不会告诉您是否可以访问 Internet,它只是告诉您是否至少有一个非环回网络适配器在工作,并且 2) 经常有由于各种原因安装的额外网络适配器使系统处于“网络可用”状态,即使您的主要 Internet 连接适配器已禁用/不可用 - 感谢Peter Duniho

由于网络不仅仅是您的路由器或网卡,而且实际上是您随时尝试连接到的任何地方的每一跳。 最简单和最可靠的方法就是 ping 一个众所周知的来源,比如谷歌,或者使用某种心跳来访问您的互联网服务之一。

这是唯一可靠的方法的原因是您与外部世界之间可能会出现任何数量的连接问题。 即使是主要的服务提供商也可能会倒闭。

因此, IMCP ping 到已知服务器(如 Google)或在WebClient上调用OpenRead是两种有效方法。 这些调用相对来说并不昂贵,并且可以放入轻量级计时器或连续任务中。

至于您的评论,您可能可以发出一个自定义事件信号来表示在一定数量的失败后网络丢失是安全的

回答你的问题

但我担心每 2 秒 ping 一次会消耗太多资源或者会导致互联网连接出现一些问题。

这两种方法在 CPU 和网络流量方面都非常便宜,使用的任何资源都应该非常少

注意:只要确保您正在 ping 或连接到具有高可用性的服务器,这将允许此类恶作剧而不仅仅是阻止您

Ping 示例

using System.Net.NetworkInformation;

// Implementation 
using (var ping = new Ping())
{
   var reply = ping.Send("www.google.com");
   if (reply != null && reply.Status != IPStatus.Success)
   {
      // Raise an event
      // you might want to check for consistent failures 
      // before signalling a the Internet is down
   }
}

// Or if you wanted to get fancy ping multiple sources
private async Task<List<PingReply>> PingAsync(List<string> listOfIPs)
{
    Ping pingSender = new Ping();
    var tasks = listOfIPs.Select(ip => pingSender.SendPingAsync(ip, 2000));
    var results = await Task.WhenAll(tasks);

    return results.ToList();
}

连接示例

using System.Net; 

// Implementation 
try
{
    using (WebClient client = new WebClient())
    {
       using (client.OpenRead("http://www.google.com/"))
       {
          // success
       }
    }
}
catch
{
    // Raise an event
    // you might want to check for consistent failures 
    // before signalling the Internet is down
}

注意:这两种方法都有一个async变体,它将返回一个Task并且可以等待更适合 IO 绑定任务的异步编程模式

资源

Ping.Send 方法

Ping.SendAsync 方法

WebClient.OpenRead 方法

WebClient.OpenReadAsync 方法

NetworkInterface.GetIsNetworkAvailable()是不可靠的……因为即使所有网络都没有连接到互联网,它也会返回true 在我看来,检查连通性的最佳方法是 ping 一个众所周知的快速在线资源。 例如:

public static Boolean InternetAvailable()
{
    try
    {
        using (WebClient client = new WebClient())
        {
            using (client.OpenRead("http://www.google.com/"))
            {
                return true;
            }
        }
    }
    catch
    {
        return false;
    }
}

无论如何,您订阅的这两个事件并不像您想象的那样工作……实际上它们检查您的网络适配器的硬件状态……而不是它们是否连接到互联网。 它们与NetworkInterface.GetIsNetworkAvailable()具有相同的缺点。 继续检查连接到一个单独的线程,该线程 ping 一个安全源并采取相应的行动。 您的Interop解决方案也非常出色。

对公共资源执行 ping 操作会给您的应用程序带来额外的调用,并增加对该网站或您将在循环中使用的任何内容的依赖。

如果您使用此方法会怎样: NetworkInterface.GetIsNetworkAvailable() 这足以满足您的应用程序的目的吗?

我在这里找到它https://docs.microsoft.com/en-us/dotnet/api/system.net.networkinformation.networkinterface.getisnetworkavailable?view=netframework-4.7.1#System_Net_NetworkInformation_NetworkInterface_GetIsNetworkAvailable

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM