如何使用.NET、C#和WPF检查互联网连接

29

我正在使用.NET、C#和WPF,我需要检查是否已经连接到某个URL,并且我找不到任何在互联网上发现的代码可以工作。

我尝试过:

Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
    IAsyncResult result = socket.BeginConnect("localhost/myfolder/", 80, null, null);
    bool success = result.AsyncWaitHandle.WaitOne(3000, true);
    if (!success)
    {
        MessageBox.Show("Web Service is down!");
    }
    else
        MessageBox.Show("Everything seems ok");
}
finally
{
    socket.Close();
}

即使我关闭本地的Apache服务器,但我总是收到一条“一切都正常”的消息。

我还尝试过:

ing ping = new Ping();
PingReply reply;
try
{
    reply = ping.Send("localhost/myfolder/");
    if (reply.Status != IPStatus.Success)
        MessageBox.Show("The Internet connection is down!");
    else
        MessageBox.Show("Seems OK");
}
catch (Exception ex)
{
    MessageBox.Show("Error: " + ex.Message);
}

但是这总是会导致异常(ping似乎只在ping服务器时有效,因此localhost有效,但localhost/myfolder/无效)

请问如何检查连接,使其对我起作用?


你是想验证你的连接是否正常(这种情况下可以使用Ping),还是某个特定的URL是否可访问? - Gabe
你只需要检查互联网连接是否正常,还是需要检查特定的网络服务是否正在运行?它们可能是两个不同的事情。 - Joe
特定的网络服务正在运行。 - Ragnar
你计划使用哪种网络服务?我怀疑是否存在一种通用的方法来检查所有网络服务类型。 - Anton Semenov
Web服务可通过端口80使用HTTP协议进行访问。 - Ragnar
显示剩余2条评论
8个回答

34

许多开发者解决这个“问题”的方式就是 ping Google.com。那么... :/ 这在大多数情况下都可以工作(99%),但是将您的应用程序工作依赖于某些外部网络服务有多专业呢?

与其 ping Google.com,不如使用一个非常有趣的 Windows API 函数叫做 InternetGetConnectedState(),它可以识别您是否能够访问互联网。

解决方案 是:

using System;
using System.Runtime;
using System.Runtime.InteropServices;
 
public class InternetAvailability
{
    [DllImport("wininet.dll")]
    private extern static bool InternetGetConnectedState(out int description, int reservedValue);
 
    public static bool IsInternetAvailable( )
    {
        int description;
        return InternetGetConnectedState(out description, 0);
    }
}

1
在一个测试案例中,我正在通过代理访问,并且代理关闭时没有浏览器页面加载,但是上述方法仍然返回true,虽然技术上并没有可用的互联网。因此,这个解决方案不是正确的。我同时使用了上述方法和连接到我的服务 :) - Rowan
“wininet.dll” 是否存在于所有 Windows 版本中? - gts13
@user2048060 :"wininet.dll" 存在于除了 Windows XP 和 Windows Server 2003 R2 以及早期版本 之外的所有 Windows 版本中。 了解更多信息,请访问:https://msdn.microsoft.com/en-us/library/windows/desktop/aa383630(v=vs.85).aspx - Anant Dabhi
2
@AnantDabhi 感谢您的资源。此外,我还发现了这个函数 https://msdn.microsoft.com/zh-cn/library/windows/desktop/aa384346%28v=vs.85%29.aspx 可以完全实现Rowan所说的功能。如果您愿意,也可以在您的回复中加入它。 - gts13
如果我想要在互联网断开连接时触发一个事件,该怎么办? - John Demetriou
这个解决方案比ping Google更快。如果你想知道,只需在单元测试中尝试两个代码即可。 - Umut D.

24

最终我使用了自己的代码:

private bool CheckConnection(String URL)
{
    try
    {
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
        request.Timeout = 5000;
        request.Credentials = CredentialCache.DefaultNetworkCredentials;
        HttpWebResponse response = (HttpWebResponse)request.GetResponse();

        if (response.StatusCode == HttpStatusCode.OK)
            return true;
        else
            return false;
    }
    catch
    {
        return false;
    }
}

有趣的是,当服务器宕机(我关闭了Apache)时,我没有收到任何HTTP状态码,而是抛出了一个异常。但这已经足够好了 :)


3
如果您想检查HTTP状态,请捕获WebException异常并查看Status属性。还有一个名为TimeOut的项。 - fa wildchild
2
最后,你只需要这样做:return (response.StatusCode == HttpStatusCode.OK); - Alireza Noori
1
我使用了这种方法,大多数情况下即使我已经连接到互联网并且网站没有问题,它仍然返回false。 - amal50

15

使用这个:

private bool CheckConnection()
{
    WebClient client = new WebClient();
    try
    {
        using (client.OpenRead("http://www.google.com"))
        {
        }
        return true;
    }
    catch (WebException)
    {
        return false;
    }
}

虽然它可以工作,但并不正确,因为我们仍然依赖于网站而不是个人电脑的互联网连接。 - Naresh
3
我已经使用这个工具多年了,但最近遇到了一个问题。我们的一位开发人员在一小时内向谷歌发送了超过5000个请求,导致应用程序被标记为拒绝服务攻击,从而被谷歌锁定。 - Rogala
我(以及我的应用程序用户)成功使用此方法。如果您想验证是否有互联网连接,通常是因为您想连接到Web服务器。确保(1)有互联网和(2)您想要的站点正在运行Web服务器的最佳方法是打开WebClient,如上所述,但使用您实际想要的地址而不是google.com。 - Skyfish

15

你可以尝试这样做:

private bool CheckNet()
{
    bool stats;
    if (System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable() == true)
    {
        stats = true;
    }
    else
    {
        stats = false;
    }
    return stats;
}

4
+1是因为它指向了NetworkInterface类。但是,如果网络已连接但无法访问互联网,我认为这种方法可能行不通。 - Richard
如果我想在它打开和关闭时收到通知,怎么办? - John Demetriou
1
这并不检查互联网连接,而只是网络适配器的状态。 - Muhammad Waqas Aziz

8

我浏览了所有的解决方案。 NetworkInterface.GetIsNetworkAvailable() 并不检查网络连接。它仅检查是否有任何网络连接可用。

Ping 不是可靠的方法,因为在许多网络中 ping 被关闭。使用 WebClient 连接到 Google 也不是100% 可靠,如果您过于频繁使用它,还会导致性能开销。

对我来说,使用 Windows NLM API 是更好的解决方案。

using NETWORKLIST;

namespace Network.Helpers
{
    public class InternetConnectionChecker
    {
        private readonly INetworkListManager _networkListManager;

        public InternetConnectionChecker()
        {
            _networkListManager = new NetworkListManager();
        }

        public bool IsConnected()
        {
            return _networkListManager.IsConnectedToInternet;
        }
        
    }
}

这是将其添加到项目中的方法。

输入图像描述


1
由于不喜欢Ping方法,这个方法让我省去了很多麻烦,非常感谢! - user1809065

7

我认为对于Windows应用程序、Windows表单或WPF应用程序来说,使用WebClient或HttpWebRequest不如以下方法更为准确:

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

    //Creating a function that uses the API function...
    public static bool IsConnectedToInternet()
    {
        int Desc;
        return InternetGetConnectedState(out Desc, 0);
    }

}

在调用write时
if(InternetCheckerCustom.CheckNet())
{
  // Do Work 
}
else
{
  // Show Error MeassgeBox 
}

1
这里有一个类似于Mahbubur Rahman的解决方案,但直接使用COM接口,无需引用Network List Manager 1.0 Type Library:
dynamic networkListManager = Activator.CreateInstance(
    Type.GetTypeFromCLSID(new Guid("{DCB00C01-570F-4A9B-8D69-199FDBA5723B}")));
    
bool isConnected = networkListManager.IsConnectedToInternet;

0

我们可以使用ping吗?

try
{
    System.Net.NetworkInformation.Ping ping = new Ping();

    //If you use DNS name as below it will give random time outs 
    //PingReply result = ping.Send("www.google.com");
   
    //INSTEAD USE IP ADDRESS LIKE BELOW IT WILL GIVE ACCURATE TIMEOUTS
    PingReply result = ping.Send("8.8.8.8");

    if (result.Status == IPStatus.Success)
        return true;
     return false;
}
catch
{
    return false;
}

Ping不总是有效,因为一些服务器会忽略ping请求。 - Skyfish
如果你想准确使用PING,你需要使用它的IP地址,而不是DNS名称。请勿使用DNS名称。 - Muhammad Waqas Aziz

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