1. 程式人生 > >C# 示例:檢測網路連線

C# 示例:檢測網路連線

       我們的應用程式的某些功能,可能需要一個網際網路連線的執行時間測試。一旦檢測到網際網路連線,可能會暫時被禁用的功能需要訪問Internet和/或使用者可以通過警報訊息通知。否則,應用程式可能會導致在操作過程中的錯誤,否則可能會導致惱人的問題.

Method 1: WebRequest

We may send a web request to a website which assumed to be online always, for example google.com. If we can get a response, then obviously the device that runs our application is connected to the internet.



	public static bool WebRequestTest()
        {
            string url = "http://www.google.com";
            try
            {
                System.Net.WebRequest myRequest = System.Net.WebRequest.Create(url);
                System.Net.WebResponse myResponse = myRequest.GetResponse();
            }
            catch
(System.Net.WebException) { return false; } return true; }

Method 2: TCP Socket

There can be some delay in response of web request therefore this method may not be fast enough for some applications. A better way is to check whether port 80, default port for http traffic, of an always online website.

	public static bool TcpSocketTest()
        {
            try
            {
                System.Net.Sockets.TcpClient client =
                    new System.Net.Sockets.TcpClient("www.google.com", 80);
                client.Close();
                return true;
            }
            catch (System.Exception ex)
            {
                return false;
            }
        }

Method 3: Ping

There can be some delay in response of web request, therefore this method may not be fast enough for some applications. A better way is to check whether port 80, default port for http traffic, of an always online website.

public bool PingTest()
        {
            System.Net.NetworkInformation.Ping ping = new System.Net.NetworkInformation.Ping();
 
            System.Net.NetworkInformation.PingReply pingStatus =
                ping.Send(IPAddress.Parse("208.69.34.231"),1000);
 
            if (pingStatus.Status == System.Net.NetworkInformation.IPStatus.Success)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

You cannot use this method in .NET Compact Framework because there is noNetworkInformationnamespace that comes with Compact Framework. However, you can use Smart Device Framework (http://www.opennetcf.com[^], Community Edition is free for download) provided by OpenNETCF. This framework comes with many other useful tools that .NET Compact Framework does not contain.

Notice that I used Google’s IP address208.69.34.231. We could use Google’s web addresswww.google.com:

  System.Net.NetworkInformation.PingReply pingStatus = ping.Send("www.google.com",1000);

However, that will require DNS lookup which causes extra delay.

Method 4: DNS Lookup

Alternatively you can use DNS lookup to check internet connectivity. This method is faster than Ping method.

	public static bool DnsTest()
        {
            try
            {
                System.Net.IPHostEntry ipHe =
                    System.Net.Dns.GetHostByName("www.google.com");
                return true;
            }
            catch
            {
                return false;
            }
        }

Method 5: Windows Internet API (WinINet)

WinINetAPI provides functions to test internet connectivity, such asInternetCheckConnectionandInternetGetConnectedState. I do not have any idea about what these fucntions do exactly to test internet connectivity. You may refer tohttp://msdn.microsoft.com/en-us/library/aa384346(v=VS.85).aspxandhttp://msdn.microsoft.com/en-us/library/aa384702(v=VS.85).aspxfor details.

An example usage can be:

	[DllImport("wininet.dll")]
        private extern static bool InternetGetConnectedState(out int connDescription, int ReservedValue);
 
	//check if a connection to the Internet can be established 
        public static bool IsConnectionAvailable()
        {
            int Desc;
            return InternetGetConnectedState(out connDesc, 0);
        }

1. win32 API函式的做法:

要用的函式:InternetGetConnectedState

函式原形:BOOL InternetGetConnectedState(LPDWORD lpdwFlags,DWORD dwReserved);

引數lpdwFlags返回當前網路狀態,,引數dwReserved依然是保留引數,設定為0即可。

INTERNET_CONNECTION_MODEM 通過調治解調器連線網路

INTERNET_CONNECTION_LAN 通過區域網連線網路

這個函式的功能是很強的。它可以:

  1. 判斷網路連線是通過網絡卡還是通過調治解調器

  2. 是否通過代理上網

  3. 判斷連線是On Line還是Off Line

  4. 判斷是否安裝“撥號網路服務”

  5. 判斷調治解調器是否正在使用

這個win32 API在系統system32資料夾中wininet.dll中

使用這個判斷的話,需要在類中這樣寫:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace API
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        
        private const int INTERNET_CONNECTION_MODEM = 1; 
        private const int INTERNET_CONNECTION_LAN = 2;

        [DllImport("wininet.dll")]
        private static extern bool InternetGetConnectedState(ref int dwFlag, int dwReserved);

        private void button1_Click(object sender, EventArgs e)
        {
            System.Int32 dwFlag = new int();
            if (!InternetGetConnectedState(ref dwFlag, 0))
            {
                MessageBox.Show("未連網!");
            }
            else if ((dwFlag & INTERNET_CONNECTION_MODEM) != 0)
            {
                MessageBox.Show("採用調治解調器上網!");
            }
            else if((dwFlag & INTERNET_CONNECTION_LAN)!=0)   
            {
                MessageBox.Show("採用網絡卡上網!");  
            }
        }
    }
}

2. 採用PING的方法 ping一個常見域名,如果ping通則網路正常

using System;
using System.Collections.Generic;
using System.Text;
using System.Net.NetworkInformation;
using System.Threading;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Ping p = new Ping();//建立Ping物件p
            PingReply pr = p.Send("10.13.88.111");//向指定IP或者主機名的計算機發送ICMP協議的ping資料包

            if (pr.Status == IPStatus.Success)//如果ping成功
            {
                Console.WriteLine("網路連線成功, 執行下面任務...");
            }
            else
            {
                int times = 0;//重新連線次數;
                do
                {
                    if (times >= 12)
                    {
                        Console.WriteLine("重新嘗試連線超過12次,連線失敗程式結束");
                        return;
                    }

                    Thread.Sleep(1000);//等待

                    pr = p.Send("10.13.88.111");

                    Console.WriteLine(pr.Status);

                    times++;

                }
                while (pr.Status != IPStatus.Success);

                Console.WriteLine("連線成功");
                times = 0;//連線成功,重新連線次數清為0;
            }
        }
    }
}

 一個完整的示例

ASP.net網站程式執行的時候,某些情況下需要判斷網路的連通狀態,包括區域網、網際網路、aol等,甚至某個具體網站的連通情況。以下類庫可以實現聯網狀態檢測:

using System;
using System.Web;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Threading;
 
namespace VvxT.Web
{
    public class Internet
    {
        #region 利用API方式獲取網路連結狀態
        private static int NETWORK_ALIVE_LAN = 0x00000001;
        private static int NETWORK_ALIVE_WAN = 0x00000002;
        private static int NETWORK_ALIVE_AOL = 0x00000004;
 
        [DllImport("sensapi.dll")]
        private extern static bool IsNetworkAlive(ref int flags);
        [DllImport("sensapi.dll")]
        private extern static bool IsDestinationReachable(string dest, IntPtr ptr);
 
        [DllImport("wininet.dll")]
        private extern static bool InternetGetConnectedState(out int connectionDescription, int reservedValue);
 
        public Internet() { }
 
        public static bool IsConnected()
        {
            int desc = 0;
            bool state = InternetGetConnectedState(out desc, 0);
            return state;
        }
 
        public static bool IsLanAlive()
        {
            return IsNetworkAlive(ref NETWORK_ALIVE_LAN);
        }
        public static bool IsWanAlive()
        {
            return IsNetworkAlive(ref NETWORK_ALIVE_WAN);
        }
        public static bool IsAOLAlive()
        {
            return IsNetworkAlive(ref NETWORK_ALIVE_AOL);
        }
        public static bool IsDestinationAlive(string Destination)
        {
            return (IsDestinationReachable(Destination, IntPtr.Zero));
        }
        #endregion
 
        /// <summary>
        /// 在指定時間內嘗試連線指定主機上的指定埠。 (預設埠:80,預設連結超時:5000毫秒)
        /// </summary>
        /// <param name="HostNameOrIp">主機名稱或者IP地址</param>
        /// <param name="port">埠</param>
        /// <param name="timeOut">超時時間</param>
        /// <returns>返回布林型別</returns>
        public static bool IsHostAlive(string HostNameOrIp, int? port, int? timeOut)
        {
            TcpClient tc = new TcpClient();
            tc.SendTimeout = timeOut ?? 5000;
            tc.ReceiveTimeout = timeOut ?? 5000;
 
            bool isAlive;
            try
            {
                tc.Connect(HostNameOrIp, port ?? 80);
                isAlive = true;
            }
            catch
            {
                isAlive = false;
            }
            finally
            {
                tc.Close();
            }
            return isAlive;
        }
 
    }
 
    public class TcpClientConnector
    {
        /// <summary>
        /// 在指定時間內嘗試連線指定主機上的指定埠。 (預設埠:80,預設連結超時:5000毫秒)
        /// </summary>
        /// <param name= "hostname ">要連線到的遠端主機的 DNS 名。</param>
        /// <param name= "port ">要連線到的遠端主機的埠號。 </param>
        /// <param name= "millisecondsTimeout ">要等待的毫秒數,或 -1 表示無限期等待。</param>
        /// <returns>已連線的一個 TcpClient 例項。</returns>
        public static TcpClient Connect(string hostname, int? port, int? millisecondsTimeout)
        {
            ConnectorState cs = new ConnectorState();
            cs.Hostname = hostname;
            cs.Port = port ?? 80;
            ThreadPool.QueueUserWorkItem(new WaitCallback(ConnectThreaded), cs);
            if (cs.Completed.WaitOne(millisecondsTimeout ?? 5000, false))
            {
                if (cs.TcpClient != null) return cs.TcpClient;
                return null;
                //throw cs.Exception;
            }
            else
            {
                cs.Abort();
                return null;
                //throw new SocketException(11001); // cannot connect
            }
        }
 
        private static void ConnectThreaded(object state)
        {
            ConnectorState cs = (ConnectorState)state;
            cs.Thread = Thread.CurrentThread;
            try
            {
                TcpClient tc = new TcpClient(cs.Hostname, cs.Port);
                if (cs.Aborted)
                {
                    try { tc.GetStream().Close(); }
                    catch { }
                    try { tc.Close(); }
                    catch { }
                }
                else
                {
                    cs.TcpClient = tc;
                    cs.Completed.Set();
                }
            }
            catch (Exception e)
            {
                cs.Exception = e;
                cs.Completed.Set();
            }
        }
 
        private class ConnectorState
        {
            public string Hostname;
            public int Port;
            public volatile Thread Thread;
            public readonly ManualResetEvent Completed = new ManualResetEvent(false);
            public volatile TcpClient TcpClient;
            public volatile Exception Exception;
            public volatile bool Aborted;
            public void Abort()
            {
                if (Aborted != true)
                {
                    Aborted = true;
                    try { Thread.Abort(); }
                    catch { }
                }
            }
        }
    }
}
 

使用方法:Default.aspx.cs

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Net.Sockets;
 
namespace VvxT.Web
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            bool IsConnected = Internet.IsConnected();
            bool IsAOLAlive = Internet.IsAOLAlive();
 
            DateTime oldTime1 = DateTime.Now;
            bool IsDestinationAlive = Internet.IsDestinationAlive("cn.yahoo.com");
            DateTime newTime1 = DateTime.Now;
            TimeSpan ts1 = newTime1 - oldTime1;
 
            bool IsLanAlive = Internet.IsLanAlive();
            bool IsWanAlive = Internet.IsWanAlive();
 
            DateTime oldTime2 = DateTime.Now;
            //bool IsHostAlive = Internet.IsHostAlive("hk.yahoo.com", null, null);//不推薦使用(無法實際控制超時時間)
            bool IsHostAlive;
            TcpClient tc = TcpClientConnector.Connect("hk.yahoo.com", null, null);//推薦使用(採用執行緒池強行中斷超時時間)
            try
            {
                if (tc != null)
                {
                    tc.GetStream().Close();
                    tc.Close();
                    IsHostAlive = true;
                }
                else
                    IsHostAlive = false;
            }
            catch { IsHostAlive = false; }
            DateTime newTime2 = DateTime.Now;
            TimeSpan ts2 = newTime2 - oldTime2;
 
            Response.Write("Connect:" + IsConnected + "<br />");
            Response.Write("Lan:" + IsLanAlive + "<br />");
            Response.Write("Wan:" + IsWanAlive + "<br />");
            Response.Write("Aol:" + IsAOLAlive + "<br />");
            Response.Write("Sip(cn.yahoo.com):" + IsDestinationAlive + " 耗時:" + ts1.TotalMilliseconds + "<br />");
            Response.Write("TcpClient(hk.yahoo.com):" + IsHostAlive + " 耗時:" + ts2.TotalMilliseconds + "<br />");
 
 
        }
    }
}
 
執行效果:
Connect:True
Lan:True
Wan:True
Aol:True
Sip(cn.yahoo.com):True 耗時:265.625
TcpClient(hk.yahoo.com):False 耗時:5000
 
當然,以上類庫也可以在C#windows程式中使用。