在 C# / .NET 應用中判斷「當前是否聯網」,看似簡單實則坑多:NetworkInterface.GetIsNetworkAvailable() 只看介面卡狀態不檢測真實互聯網連通性;Ping 可能被防火牆封鎖;HttpClient 請求外網引入依賴與延遲。本文對比 WinINET API (系統級)、NetworkInterface + Ping (框架級)、HttpClient/HTTP 請求 (應用級) 三大方案,提供生產級代碼模板與選型建議。
調用 Windows 核心 `wininet.dll` 導出函數,直接讀取系統維護的連接狀態標誌 (包含調制解調器、LAN、代理、離線模式等)。
using System;
using System.Runtime.InteropServices;
namespace NetworkUtils
{
public static class WinInetDetector
{
// 導入 wininet.dll
[DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool InternetGetConnectedState(out int lpdwFlags, int dwReserved);
// 連接狀態標誌位 (部分常用)
[Flags]
public enum ConnectionState : int
{
INTERNET_CONNECTION_MODEM = 0x01, // 調製解調器
INTERNET_CONNECTION_LAN = 0x02, // 區域網路
INTERNET_CONNECTION_PROXY = 0x04, // 代理
INTERNET_CONNECTION_MODEM_BUSY = 0x08, // Modem 忙
INTERNET_RAS_INSTALLED = 0x10, // RAS 安裝
INTERNET_CONNECTION_OFFLINE = 0x20, // 離線模式
INTERNET_CONNECTION_CONFIGURED = 0x40 // 已配置連線
}
///
/// 檢測是否有活躍的網際網路連線 (系統級判斷)
///
/// true: 系統認為有連線; false: 離線/無連線
public static bool IsConnectedToInternet()
{
int flags = 0;
try
{
bool result = InternetGetConnectedState(out flags, 0);
// 可選:解析 flags 判斷具體連線類型
// Console.WriteLine($"Flags: {(ConnectionState)flags}");
return result;
}
catch (Exception ex)
{
// 記錄日誌
return false;
}
}
///
/// 獲取詳細連線類型標誌
///
public static ConnectionState GetConnectionFlags()
{
int flags = 0;
InternetGetConnectedState(out flags, 0);
return (ConnectionState)flags;
}
}
}
bool online = WinInetDetector.IsConnectedToInternet();
Console.WriteLine($"系統級聯網狀態: {online}");
if (online)
{
var flags = WinInetDetector.GetConnectionFlags();
Console.WriteLine($"連線類型: {flags}");
if (flags.HasFlag(WinInetDetector.ConnectionState.INTERNET_CONNECTION_LAN))
Console.WriteLine("-> 區域網路連接");
if (flags.HasFlag(WinInetDetector.ConnectionState.INTERNET_CONNECTION_PROXY))
Console.WriteLine("-> 通過代理上網");
}
| 優點 | 缺點 |
|---|---|
| 零依賴、極快 (微秒級)、無網路封包發送、系統級權威、可識別代理/離線模式/調制解調器 | 僅反映「系統認為有連線」,不保證能訪問互聯網 (如:連著路由器但路由器斷網、Portal 認證頁、企業內網無外網權限),會有誤報「在線」 |
using System.Net.NetworkInformation;
using System.Net;
public static class NetworkDetector
{
///
/// 綜合判斷:介面卡 UP + 能 Ping 通可靠公共節點
///
public static bool IsInternetAvailable(string host = "114.114.114.114", int timeoutMs = 3000)
{
// 1. 快速檢查:至少有一張非回環、非隧道、運作狀態 Up 的介面卡
if (!NetworkInterface.GetIsNetworkAvailable())
return false;
foreach (var ni in NetworkInterface.GetAllNetworkInterfaces())
{
if (ni.OperationalStatus != OperationalStatus.Up) continue;
if (ni.NetworkInterfaceType == NetworkInterfaceType.Loopback) continue;
if (ni.NetworkInterfaceType == NetworkInterfaceType.Tunnel) continue; // Teredo/6to4/VPN 虛擬介面
// 可選:過濾虛擬機/虛擬適配器 (名稱含 "Virtual", "VMware", "Hyper-V", "Docker")
if (ni.Description.IndexOf("Virtual", StringComparison.OrdinalIgnoreCase) >= 0) continue;
if (ni.Description.IndexOf("VMware", StringComparison.OrdinalIgnoreCase) >= 0) continue;
// 2. 深度檢測:Ping 可靠公共 DNS (UDP/TCP 53 不通用,這裡用 ICMP)
try
{
using (var ping = new Ping())
{
var reply = ping.Send(host, timeoutMs);
if (reply.Status == IPStatus.Success)
return true; // 真正通往互聯網
}
}
catch { /* 忽略 Ping 異常 */ }
}
return false;
}
///
/// 異步版本 (避免阻塞 UI 線程)
///
public static async Task IsInternetAvailableAsync(string host = "114.114.114.114", int timeoutMs = 3000)
{
if (!NetworkInterface.GetIsNetworkAvailable()) return false;
try
{
using (var ping = new Ping())
{
var reply = await ping.SendPingAsync(host, timeoutMs);
return reply.Status == IPStatus.Success;
}
}
catch { return false; }
}
}
| 優點 | 缺點 |
|---|---|
| 純 .NET 標準庫、跨平台 (Win/Linux/macOS .NET Core/5+)、可驗證真實 IP 通達性、可自定義目標/超時、支援異步 | ICMP 可能被防火牆/路由器/運營商封禁/限流導致誤判「離線」;需選擇高可用測試目標 (多 IP 輪詢) |
using System.Net.Http;
using System.Threading.Tasks;
public static class HttpDetector
{
private static readonly HttpClient _client = new HttpClient
{
Timeout = TimeSpan.FromSeconds(5)
};
// 靜態構造函數配置 (僅執行一次)
static HttpDetector()
{
_client.DefaultRequestHeaders.ConnectionClose = false; // Keep-Alive
_client.DefaultRequestHeaders.UserAgent.ParseAdd("NetworkHealthCheck/1.0");
}
///
/// 請求可靠的 HTTP 端點驗證真實應用層連通性
///
public static async Task IsInternetReachableAsync(
string url = "https://www.msftconnecttest.com/redirect", // 微軟 NCSI 端點,返回 200 OK
HttpCompletionOption completionOption = HttpCompletionOption.ResponseHeadersRead)
{
try
{
using (var request = new HttpRequestMessage(HttpMethod.Head, url))
{
var response = await _client.SendAsync(request, completionOption);
return response.IsSuccessStatusCode; // 2xx
}
}
catch (HttpRequestException)
{
return false;
}
catch (TaskCanceledException) // Timeout
{
return false;
}
}
///
/// 多端點輪詢策略 (提高可靠性)
///
public static async Task IsInternetReachableMultiAsync()
{
var endpoints = new[]
{
"https://www.msftconnecttest.com/redirect", // 微軟 NCSI
"https://connect.rom.miui.com/generate_204", // 小米/Android 檢測端點
"https://captive.apple.com/hotspot-detect.html", // Apple
"https://www.google.com/generate_204", // Google (HTTPS)
"https://www.baidu.com/" // 國內備用
};
var tasks = endpoints.Select(url => IsInternetReachableAsync(url)).ToArray();
var results = await Task.WhenAll(tasks);
return results.Any(r => r); // 任一成功即視為在線
}
}
https://www.msftconnecttest.com/redirect (微軟官方,返回 200 + 頁面含 "Microsoft NCSI")https://msftconnecttest.com/connecttest.txt (返回 "Microsoft NCSI")https://connect.rom.miui.com/generate_204 (小米/安卓標準,返回 204 No Content)https://captive.apple.com/hotspot-detect.html (蘋果,返回 "Success")https://www.google.com/generate_204 (Google,204)優勢: 走真實 HTTP/TCP/TLS 棧,驗證 DNS 解析、TCP 握手、TLS 協商、HTTP 協議、代理穿透、Portal 認證攔截 — 最貼近用戶實際體驗。
| 優點 | 缺點 |
|---|---|
| 應用層真實驗證、支援 HTTPS/TLS/代理/重試/超時控制、跨平台 .NET Core/5+、可攜帶業務邏輯 (如檢查 API 健康) | 依賴 HttpClient/SSL/TLS 堆疊、較重 (首次冷啟動較慢)、需網路往返 (百毫秒級)、外部端點可用性依賴 |
// 推薦組合:快速預檢 (WinINET) + 深度驗證 (Ping/HttpClient)
public static class NetworkHealth
{
public static async Task CheckAsync()
{
// Level 1: 系統級極速預檢 (微秒)
if (!WinInetDetector.IsConnectedToInternet())
return NetworkStatus.Offline; // 系統級離線 (飛行模式/禁用網卡/拔網線)
// Level 2: ICMP 深度檢測 (10-50ms)
if (await NetworkDetector.IsInternetAvailableAsync())
return NetworkStatus.Online; // 真實 IP 通達
// Level 3: HTTP 應用層驗證 (50-500ms) - 針對 Portal/代理/僅 HTTP 通的場景
if (await HttpDetector.IsInternetReachableMultiAsync())
return NetworkStatus.PortalOrRestricted; // 可能需 Web 認證/僅 HTTP 白名單
return NetworkStatus.Offline;
}
}
public enum NetworkStatus { Online, PortalOrRestricted, Offline }
true。C# 檢測網絡狀態,沒有銀彈,只有分級組合。WinINET 看系統認知、Ping 看 IP 通達、HttpClient 看應用層真實可用。根據業務敏感度 (即時通訊/交易/後台同步/離線優先) 選擇合適層級或組合,並做好緩存、異步、多端點容錯,才能構建健壯的網絡感知能力。