在实际的应用开发中,我们的应用程序经常需要在运行时侦测当前系统的网络连通性,特别是在应用程序需要访问网络的时候,可以通过运行时的侦测网络连通性,及时反馈给用户,以便用户做出正确的选择;也可以在得到侦测结果后,系统根据网络的连通性状态做出相应的处理,比如在需要网络访问才能正常使用的应用程序中,一旦检测到网络不能正常使用之后,做出相应的处理,可以更好的防止不必要错误异常发生。当前系统.NET进行网络的连通性侦测有很多种方法,本文将使用.NET(C#/VB)代码展示多种具有代表性且比较简易的方法来检测网络的连通性。
第一种方法:使用WebRequest/HttpWebRequest对象来访问指定的主机名。代码如下:
//通过访问网页的方式确定当前系统的连通性
//需要注意,选择的主机名/域名必须确保异常的可能性尽可能小
public bool HttpRequestMonitor(string host)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(host);
request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36";
request.Method = "GET";
try
{
using (HttpWebResponse response = ((HttpWebResponse)request.GetResponse()))
{
return true;
}
}
catch (Exception ex)
{
return false;
}
return true;
}
上面使用的是HttpWebRequest的方式来检测,你也可以直接使用WebRequest,代码如下:
//需要确保主机名/域名的连通性高
public static bool WebRequestMonitor(string host)
{
try
{
WebRequest myRequest = WebRequest.Create(host);
WebResponse myResponse = myRequest.GetResponse();
}
catch (WebException)
{
return false;
}
return true;
}
这两种方法都可以达到检测的目的,优势是方便理解,也能快速上手,但有一个劣势,就是用来检测的网站域名必须要能够确保长时间正常在线,如果要访问的域名出现故障,那么检测将不准确。
第二种方法:TCP Socket检测,这里可以使用主机名,也可以使用IP地址。使用主机名/域名的方式如下:
//使用主机名方式来检测连通性
// 如果是域名,后面的port一般为80
public static bool TcpSocketMonitor(string host, int port)
{
try
{
using(TcpClient client = new TcpClient(host, port))
{
client.Close();
}
}
catch (Exception ex)
{
return false;
}
return true;
}
使用IP地址来访问:
//基本和使用主机名检测的方法类似.
public static bool TcpSocketMonitorByIp(string ip, int port)
{
try
{
using (TcpClient client = new TcpClient(new IPEndPoint(IPAddress.Parse(ip), port)))
{
client.Close();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return false;
}
return true;
}
这种方法的优势也是使用难度不高,劣势同样是选择的目标必须在线率高,不然会存在不稳定的现象。如果使用IP的方式,可以使用两台机器进行互相检测,这样可以比较好的规避在线率的问题。
第三种方法:也就是我们常用的Ping了,Ping同样可以使用主机名/域名或者IP,代码如下:
//使用主机名/域名的方式来检测网络的连通性
public bool PingServer(string host)
{
try
{
Ping ping = new Ping();
PingReply replye = ping.Send(host, 1000);
//如果使用IP,那么只需ping.Send(IPAddress.Parse(host), 1000)这种方式即可
return replye.Status == IPStatus.Success;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return false;
}
}
这种方式比前面的方法有一定的优势,即无需对指定端口的访问,但劣势同样和前面的一样,依赖目标服务器,并且很有可能会出现禁Ping的情况。如果是内部的服务器相互Ping,效果会好些。
第四种方法:使用DNS来检测网络的连通性,这种方法是通过DNS来获取域名的IP,代码如下:
//请求DNS返回域名的IP,如果没有错误,说明网络连通
public bool DnsLookup(string host)
{
try
{
IPHostEntry ipHE = Dns.GetHostEntry(host);
return true;
}
catch (Exception ex)
{
//Console.WriteLine(ex.Message);
return false;
}
}
这个方法优于前面三种方法,而且前面三种方法的基础也是DNS,因此用这种方法应该是当前最佳的。优势是简单,并且一般不太可能出现DNS异常的情况。
第五种方法:使用Windows Internet API (WinINet)来操作,这个方法来源于网络[1],一般比较少使用这种方式,代码如下:
[DllImport("wininet.dll")]
private extern static bool InternetGetConnectedState(out int connDescription, int ReservedValue);
//尝试建立到互联网的连接来检测连通性
public static bool IsConnectionAvailable()
{
int Desc;
return InternetGetConnectedState(out connDesc, 0);
}
第六种方法:使用WMI的方式确定当前网络的连通性[2]。该方法是使用WMI来PING,方法比较复杂,需要了解WMI的方法,具体方法如下:
strComputer = "."
Set objWMIService = GetObject(_
"winmgmts:\\" & strComputer & "\root\cimv2")
Set colPings = objWMIService.ExecQuery _
("Select * From Win32_PingStatus where Address = '192.168.1.1'")
For Each objStatus in colPings
If IsNull(objStatus.StatusCode) _
or objStatus.StatusCode<>0 Then
WScript.Echo "Computer did not respond."
Else
Wscript.Echo "Computer responded."
End If
Next
在实际使用中,个人比较喜欢选用DNS的方式来确定网络连通性,当然也不一定,在实际情况中,根据自己的需求选择适当的方式即可。
附注:
1. 本文的大部分方法都可以在这里找到:http://www.codeproject.com/Tips/147662/Testing-Internet-Connectivity
非常感谢作者的耐心和细心分类,由于全部是英文,我权当翻译了一下好了,很多没有实际中使用的方法,本文直接引用了原文的例子,有的稍作修改。
2. WMI的方式是在微软官方网站中的例子,你可以在这里找到:http://msdn.microsoft.com/en-us/library/windows/desktop/aa394595(v=vs.85).aspx