判斷連網的方法介紹 1. InternetGetConnectedState 此函數獲取網路狀態有延時,且對網卡傷害較大 MSDN官方自己推薦不建議使用,不管是連網狀態下還是斷網情況下,獲取的網路狀態都有不准確的案例,如下: (BUG) InternetGetConnectedState API r ...
判斷連網的方法介紹
1. InternetGetConnectedState
- 此函數獲取網路狀態有延時,且對網卡傷害較大
- MSDN官方自己推薦不建議使用,不管是連網狀態下還是斷網情況下,獲取的網路狀態都有不准確的案例,如下:
(BUG) InternetGetConnectedState API returns false result
Detecting LAN connection using InternetGetConnectedState API doesn't work
https://bbs.csdn.net/topics/340141699
在看下文之前,可以瀏覽MSDN:通過InternetGetConnectedState方法對網路狀態的獲取
如上InternetGetConnectedState方法介紹中
- dwReversed必須設置為0
- 通過輸出值lpdwFlags可以獲取當前網路連接的信息,通過拼裝對比可以得到當前連接的網路類型,如撥號上網/區域網等
bool InternetGetConnectedState( out LPDWORD lpdwFlags, int dwReversed);
首先,添加非托管函數並調用,可以獲取網路是否聯網
//聲明外部的函數
[DllImport("winInet.dll ")]
private static extern bool InternetGetConnectedState(ref int flag,int dwReserved);
2. IsNetworkAlive
需要服務System Event Notification的支持(系統預設自動啟動該服務),且需要安裝最新的SDK(如.NET)
由API中翻譯:該功能可在Windows XP、2000(或Windows NT 4.0與Internet Explorer 5或更高版本)上使用,在windows95或更高版本上使用Internet Explorer 5或更高版本。所以,一般的系統都是支持的
輸出值lpdwFlags
具體類型的詳細內容可鏈接QOCINFO structure
- NETWORK_ALIVE_LAN=1 區域網(此處並非指有線網)
- NETWORK_ALIVE_WAN=2 遠程訪問-撥號訪問和vpn訪問(此處並非只無線網,按DPI所示,指的是RAS connections)
- NETWORK_ALIVE_AOL=4 無效的值。。。因為只有Win9x系統才有此第三個選項。參考鏈接
無線網路的判斷:lpdwFlags對是否無線網路,並沒有直接的判斷。
eg:比如我的電腦環境(有線網路或者wifi網路),獲取的flag=1(區域網)
返回值(bool)
- 當返回值為true,且無錯誤Code時,表示網路已連接
- 當返回值為false,且無錯誤Code時,表示網路未連接
那麼,錯誤Code(異常)怎麼獲取呢?
3. 獲取上一次異常Code-GetLastError
此處推薦使用Marshal中的GetLastWin32Error,見如下源代碼:
1 /// <summary>
2 /// 通過使用平臺調用的最後一個非托管函數返回的錯誤代碼返回調用具有 <see cref="F:System.Runtime.InteropServices.DllImportAttribute.SetLastError" /> 標誌設置。
3 /// </summary>
4 /// <returns>最後一個錯誤代碼設置通過調用 Win32 SetLastError 函數。</returns>
5 [SecurityCritical]
6 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
7 [MethodImpl(MethodImplOptions.InternalCall)]
8 public static extern int GetLastWin32Error();
GetLastWin32Error可獲取最後一個非托管函數的錯誤Code
int errCode = Marshal.GetLastWin32Error();
--獲取 error code的詳細描述信息,可參考https://my.oschina.net/kavensu/blog/264273
值得註意的是,非托管函數聲明時,要添加SetLastError=true;如:
1 [DllImport("sensapi.dll", SetLastError = true)]
2 private static extern bool IsNetworkAlive(out int connectionDescription);
4. 使用Ping函數
1 using (var ping = new Ping())
2 {
3 //ping給定的host 如:www.baidu.com,超時時間為1s
4 var reply = ping.Send(host, 1000);
5 var pingResult= reply != null && reply.Status == IPStatus.Success;
6 }
推薦判斷電腦連接網路的方案
如上,獲取網路狀態是否連接,建議通過IsNetworkAlive函數獲取。那麼IsNetworkAlive是否準確呢?
答案是否!
案例:
- 電腦配置了虛擬機連接--斷網後,IsNetworkAlive返回的是有網true !-- 對虛擬機等網路是否連接不能判斷。
- 在某些情況下,光纖等壞了,上不了網路,但是走TCP協議可以聊微信QQ--IsNetworkAlive返回的是有網true !
無網路時,有可能返回有網:lpdwFlags=1 區域網時,如果當前配置了虛擬機連接之類的,本機無法連接網路時,IsNetworkAlive函數還是會返回true。如下:
如果是區域網且IsNetworkAlive返回true,則使用InternetGetConnectedState重新獲取網路狀態。
1 //通過IsNetworkAlive方法,來獲取電腦的聯網狀態 2 [DllImport("sensapi.dll", SetLastError = true)] 3 private static extern bool IsNetworkAlive(out int connectionDescription); 4 5 //通過InternetGetConnectedState方法,來獲取電腦的聯網狀態 6 [DllImport("winInet.dll")] 7 private static extern bool InternetGetConnectedState(ref IntPtr dwFlag, int dwReserved); 8 9 /// <summary> 10 /// IsNetworkAlive函數輸出值1-連接區域網 11 /// </summary> 12 private const int LanNetworkConnectedFlag = 1; 13 /// <summary> 14 /// 網路是否連接 15 /// </summary> 16 public static bool IsConnected 17 { 18 get 19 { 20 var isNetworkConnected = IsNetworkAlive(out int flags); 21 int errCode = Marshal.GetLastWin32Error(); 22 if (errCode != 0) 23 { 24 Console.WriteLine($"通過{nameof(IsNetworkAlive)}非托管DLL函數,獲取網路狀態時,遇到異常!"); 25 } 26 27 //IsNetworkAlive檢測到是區域網連上網路,則使用InternetGetConnectedState重新確認是否有網 28 if (isNetworkConnected && flags == LanNetworkConnectedFlag) 29 { 30 var dwFlag = new IntPtr(); 31 isNetworkConnected = InternetGetConnectedState(ref dwFlag, 0); 32 errCode = Marshal.GetLastWin32Error(); 33 if (errCode != 0) 34 { 35 Console.WriteLine($"通過{nameof(InternetGetConnectedState)}非托管DLL函數,獲取網路狀態時,遇到異常!"); 36 } 37 } 38 39 return isNetworkConnected; 40 } 41 }