确定互联网连接是否可用

13
我知道我不是第一个提出这个问题的人:怎样才能知道我的应用程序是否在线? 我找到了这篇文章:StackOverflow。 我想使用C#和.NET 3.5实现它。
推荐的方法是定期ping资源,但我对此建议并不满意。我宁愿检测网络变化,然后再ping我的服务来检查它是否在线。
.NET为此提供了两个事件: NetworkChange.NetworkAvailabilityChanged NetworkChange.NetworkAddressChanged
第一个事件听起来不错,但仅在最后一个联网的网络卡脱机时触发。我有几个由VMWare安装的虚拟网络卡(始终在线),因此该事件无法满足我的需求。 第二个事件可以工作,但在插上网络电缆和触发事件之间通常需要等待5秒钟。 当我拔掉电缆时,Windows托盘图标的反应几乎是立即的。 有没有更快的方法?
我的解决方法是每500毫秒轮询一次 NetworkInterface.GetAllNetworkInterfaces(),并在网络适配器状态改变时抛出自己的事件。
一定有更好的解决方案 :)

你们计划如何检测所有相关的网络变化?实际上,如果沿途丢失了一些重要的链接,你们的应用程序是无法察觉到它们的。 - Brian Rasmussen
请查看我的编辑,其中包含有关Iphlpapi.dll和NotifyAddrChange的新信息。 - Webleeuw
在线是什么意思?有服务器吗?如果你和服务器保持在线状态,为什么不每5秒发送一个状态消息来确定你是否在线呢? - user195488
当ISP中断时,没有要触发的.NET事件。你确实需要ping一个远程资源,即使如此,你也只知道你可以访问该远程资源。防火墙和代理可能允许或不允许访问其他资源。 - dotancohen
8个回答

10

我尝试了Webleeuw建议的链接,但是那段代码在我插拔电缆时也需要4到10秒的时间来通知我。 现在,我想知道这是我的电脑还是安装的问题,于是我编写了自己的Observer类,它基于NetworkInterface.GetAllNetworkInterfaces()。

而且:它的速度非常快。我的应用程序现在与托盘一样快地响应。 这段代码远未达到生产代码的水平,只是一个快速的hack。但这是我现在要构建的基础 :)

using System;
using System.Net.NetworkInformation;
using Timer=System.Threading.Timer;

namespace NetworkCheckApp
{
public class NetworkStatusObserver
{
    public event EventHandler<EventArgs> NetworkChanged;

    private NetworkInterface[] oldInterfaces;
    private Timer timer;

    public void Start()
    {
        timer = new Timer(UpdateNetworkStatus, null, new TimeSpan(0, 0, 0, 0, 500), new TimeSpan(0, 0, 0, 0, 500));

        oldInterfaces = NetworkInterface.GetAllNetworkInterfaces();
    }

    private void UpdateNetworkStatus(object o)
    {
        var newInterfaces = NetworkInterface.GetAllNetworkInterfaces();
        bool hasChanges = false;
        if (newInterfaces.Length != oldInterfaces.Length)
        {
            hasChanges = true;
        }
        if (!hasChanges)
        {
            for (int i = 0; i < oldInterfaces.Length; i++)
            {
                if (oldInterfaces[i].Name != newInterfaces[i].Name || oldInterfaces[i].OperationalStatus != newInterfaces[i].OperationalStatus)
                {
                    hasChanges = true;
                    break;
                }
            }
        }

        oldInterfaces = newInterfaces;

        if (hasChanges)
        {
            RaiseNetworkChanged();
        }
    }

    private void RaiseNetworkChanged()
    {
        if (NetworkChanged != null)
        {
            NetworkChanged.Invoke(this, null);
        }
    }
}
}

1
很遗憾我的编辑没有帮到你,但是你自己提供的解决方案很好:)。我将来可能会在自己的项目中使用它,所以感谢你在这里提供它。 - Webleeuw

2

尝试使用NetworkChange类实现此操作。

using System.Net.NetworkInformation

private void Form5_Load(object sender, EventArgs e)
{
    NetworkChange.NetworkAvailabilityChanged += new NetworkAvailabilityChangedEventHandler(NetworkChange_NetworkAvailabilityChanged);
}

private void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
{
    if (e.IsAvailable)
    {
        MessageBox.Show("Available");
    }
    else
    {
        MessageBox.Show("Not available");
    }
}

1
这仅适用于一个网络。如果您有多个网络,则只有在所有网络离线时才会触发事件。这对我的情况没有帮助(请参见我的描述)。 - Kay

2

这里的人已经说过了,网络可用性和互联网可用性是有区别的。
你可以在你的网络接口和本地路由器之间拥有网络可用性,但在本地路由器和你的互联网服务提供商(ISP)之间可能没有互联网可用性。
另一个问题是通过ping测试只会告诉你关于互联网可用性,但不会告诉你是哪个网络接口提供的,我认为唯一的方法是强制通过一个接口进行ping测试,但在Windows上不可能。


0
定期对您的资源进行ping操作是唯一的选择,可以在服务离线以及客户端离线时通知您。您可能希望同时处理这两种情况。

是的,我知道。对我来说,特定用户的网络不可用的风险要比服务器不可用的风险高得多。我们会进行ping测试,但不是定期进行,只有在应用程序启动和网络发生变化时才进行。也许我们会定期进行ping测试,但不是每500毫秒一次 :) - Kay

0

Windows系统托盘图标很可能与网络适配器驱动程序相关联,即在操作系统级别之下,这就是为什么它可以如此快速地响应。

由于网络适配器只是客户端和其在互联网上访问的服务之间众多链接中的一个,因此检测互联网是否可用的唯一可靠方法是轮询互联网上的某些服务,就像ping所做的那样。在TCP/IP网络中,这被称为保持活动状态,许多协议将其作为选项内置其中。


0
关于ping的问题:根据你希望如何解释结果,ping似乎对我来说并不是十分可靠。如果目标偶尔超时,而连接仍然保持活动状态怎么办?我还没有见过从不响应ping的服务器。
如果你问我,每隔X毫秒检查网络接口是否仍然在线(NetworkInterface.OperationalStatus属性)似乎更可靠。
编辑:这篇文章处理比System.Net.NetworkInformation.NetworkChange类更低级别的网络地址事件,或者看起来是这样。在我的电脑上它运行得非常快,所以希望你能使用那个解决方案。

谢谢提供链接。我看了一下,似乎使用了NetworkChange。这很有用,但我不太满意,因为它太慢了。 - Kay
“我还没有见过从不响应ping的服务器” - 这是一个错误的假设。许多网络会丢弃ICMP数据包。 - user195488
@Roboto:我不理解你的评论,可能是由于一些小的沟通差异 : )。我的意思是指出 ping 不可靠的事实,因为即使服务器在线,它也可能会丢失一个或多个 ping 数据包。更明确地说:我还没有见过每次都能响应每个 ping 的服务器。 - Webleeuw

0

你可以使用ping,但我也会构建一个简单的调用来返回“是”的结果,如果服务器在线的话。这样你就知道服务器是否在线,并且正在运行你的代码。此外,我只会在需要网络资源时才进行调用或ping,而不是持续进行。


0

进行ping操作绝对不是最干净的选择,特别是当它是一个Web服务器时。一些主机会禁用对ICMP流量的响应,因此您可能会ping但无法获得响应。如果出现异常,何不优雅地处理它呢?


1
实际上,我并没有发送“ping”命令。相反,我正在调用我的Web服务器上的Web服务。这将告诉我我的WCF服务是否仍然在运行 :) - Kay

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