多线程应用中调用API时如何持续检测网络连接?
我来给你几个实用的解决方案,刚好匹配你的需求:
1. 靠谱的网络状态检测方法
首先你需要一个准确的方法判断网络是否可用——单纯用NetworkInterface.GetIsNetworkAvailable()有时候会误判(比如网卡插着但没联网),所以我们可以写一个更严谨的版本:
using System.Net.NetworkInformation; using System.Linq; private bool IsNetworkAvailable() { // 遍历所有非回环、非隧道的网络接口 foreach (var networkInterface in NetworkInterface.GetAllNetworkInterfaces()) { // 接口必须处于启用状态,且有有效的IPv4/IPv6地址 if (networkInterface.OperationalStatus == OperationalStatus.Up && networkInterface.NetworkInterfaceType != NetworkInterfaceType.Loopback && networkInterface.NetworkInterfaceType != NetworkInterfaceType.Tunnel) { var ipProps = networkInterface.GetIPProperties(); if (ipProps.UnicastAddresses.Any(ua => ua.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork || ua.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)) { return true; } } } return false; }
2. 等待网络恢复的逻辑
如果检测到网络不可用,我们需要暂停等待,但不能让线程空转占用CPU。这里提供同步和异步两种版本:
同步版本(适合ThreadPool的传统用法)
private void WaitForNetwork() { // 每5秒检查一次网络状态,避免CPU空转 while (!IsNetworkAvailable()) { System.Threading.Thread.Sleep(5000); } }
异步版本(推荐,更高效)
private async System.Threading.Tasks.Task WaitForNetworkAsync(System.Threading.CancellationToken cancellationToken = default) { while (!IsNetworkAvailable()) { await System.Threading.Tasks.Task.Delay(5000, cancellationToken); cancellationToken.ThrowIfCancellationRequested(); } }
3. 结合ThreadPool的完整调用逻辑
另外注意你的原API代码有资源泄漏风险——HttpWebResponse和StreamReader必须用using包裹,确保资源被正确释放。下面是整合后的代码:
传统ThreadPool版本
// 封装API请求,确保资源释放 private void MakeApiRequest() { try { string url = settings.Get("URL"); using (var httpRequest = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url)) { httpRequest.Method = "GET"; using (var res = (System.Net.HttpWebResponse)httpRequest.GetResponse()) using (var sr = new System.IO.StreamReader(res.GetResponseStream(), System.Text.Encoding.Default)) { string response = sr.ReadToEnd(); // 在这里处理API返回的内容,比如解析、存储等 } } } catch (System.Net.WebException ex) { // 处理请求异常,比如网络中途断开的情况 System.Console.WriteLine($"API请求失败: {ex.Message}"); // 可以根据需要添加重试逻辑 } } // 提交到ThreadPool的工作项 private void ApiWorkItem(object state) { // 先等待网络恢复 WaitForNetwork(); // 网络可用后发起请求 MakeApiRequest(); } // 调用方式 System.Threading.ThreadPool.QueueUserWorkItem(ApiWorkItem);
异步Task版本(推荐,更符合.NET现代编程模式)
如果可以的话,用Task.Run代替ThreadPool的旧方法(内部还是用ThreadPool,但异步支持更好):
// 异步API请求方法 private async System.Threading.Tasks.Task MakeApiRequestAsync() { try { string url = settings.Get("URL"); using (var httpRequest = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url)) { httpRequest.Method = "GET"; using (var res = (System.Net.HttpWebResponse)await httpRequest.GetResponseAsync()) using (var sr = new System.IO.StreamReader(res.GetResponseStream(), System.Text.Encoding.Default)) { string response = await sr.ReadToEndAsync(); // 处理返回内容 } } } catch (System.Net.WebException ex) { System.Console.WriteLine($"API请求失败: {ex.Message}"); } } // 异步工作项 private async System.Threading.Tasks.Task ApiWorkItemAsync() { await WaitForNetworkAsync(); await MakeApiRequestAsync(); } // 调用方式 _ = System.Threading.Tasks.Task.Run(ApiWorkItemAsync);
4. 进阶优化:事件驱动的网络监听
如果不想轮询网络状态,可以用.NET自带的网络变化事件,这样网络恢复时立即触发请求,更高效:
// 在应用启动时注册事件 System.Net.NetworkInformation.NetworkChange.NetworkAvailabilityChanged += NetworkChange_NetworkAvailabilityChanged; private void NetworkChange_NetworkAvailabilityChanged(object sender, System.Net.NetworkInformation.NetworkAvailabilityEventArgs e) { if (e.IsAvailable) { System.Console.WriteLine("网络已恢复,开始发起API请求"); System.Threading.ThreadPool.QueueUserWorkItem(ApiWorkItem); } else { System.Console.WriteLine("网络已断开,暂停API请求"); } }
内容的提问来源于stack exchange,提问作者Desh
相关产品推荐
相关产品推荐

