我正在写一个应用程序,我必须扫描一个IP(内联网)范围,并查看特定的IP是否对应于特定的URL。例如,假设我们有url:http://<ip>:8080/x/y
,我们想看看能否找到一个在192.168.1.1 - 192.168.1.254范围内运行的活动服务器。显然,扫描过程不应该阻止用户界面。多个HttpClient异步请求到一个IP范围
所以我创建了下面的异步方法:
private List<AvailableServer> _availableServerList;
public List<AvailableServer> AvailableServerList
{
get { return _availableServerList;}
set { _availableServerList = value;}
}
private Mutex objLock = new Mutex(true, "MutexForScanningServers");
private long IPsChecked;
private List<string> allPossibleIPs;
CancellationTokenSource cts;
public async Task GetAvailableServers()
{
Dictionary<string, string> localIPs = LocalIPAddress(); //new Dictionary<string, string>();
allPossibleIPs = new List<string>();
Dictionary<string, CancellationToken> kvrList = new Dictionary<string, CancellationToken>();
cts = new CancellationTokenSource();
foreach (KeyValuePair<string, string> kvp in localIPs)
{
allPossibleIPs.AddRange(getIpRange(kvp.Key.ToString(), kvp.Value.ToString()));
}
foreach (string ip in allPossibleIPs)
{
kvrList.Add(ip, cts.Token);
}
AvailableServerList = new List<AvailableServer>();
var downloads = kvrList.Select(kvr => isServerAvailableAsync(kvr));
Task[] dTasks = downloads.ToArray();
await Task.WhenAll(dTasks).ConfigureAwait(false);
}
,其目的是要开始的任务banch,试图获得一个有效的HttpClient要求他们中的每一个。假设请求是有效的,如果HttpClient.GetStringAsync不抛出任何异常:
private async Task isServerAvailableAsync(Object obj)
{
using (var client = new HttpClient())
{
try
{
KeyValuePair<string, CancellationToken> kvrObj = (KeyValuePair<string, CancellationToken>)obj;
string urlToCheck = @"http://" + kvrObj.Key + ":8080/x/y";
string downloadTask = await client.GetStringAsync(urlToCheck).ConfigureAwait(false);
string serverHostName = Dns.GetHostEntry(kvrObj.Key).HostName;
AvailableServerList.Add(new AvailableServer(serverHostName, @"http://" + serverHostName + ":8080/x/y"));
// }
}
catch (System.Exception ex)
{
//...Do nothing for now...
}
finally
{
lock (objLock)
{
//kvrObj.Value.ThrowIfCancellationRequested();
IPsChecked++;
int tmpPercentage = (int)((IPsChecked * 100)/allPossibleIPs.Count);
if (IPsCheckedPercentageCompleted < tmpPercentage)
{
IPsCheckedPercentageCompleted = tmpPercentage;
OnScanAvailableServersStatusChanged(new EventArgs());
}
}
}
}
}
如果请求是有效的,那么我们发现一个可用的服务器,因此我们将该网址添加到我们的名单。否则我们会发现一个例外。最后,我们更新我们的百分比变量,因为我们想将它们传递给我们的用户界面(xx%扫描)。每次任务完成时,它会触发由我们的用户界面使用的委托来获取可用服务器的新更新列表并完成百分比。 主要异步函数GetAvailableServers开始经由Task.Run(()=> className.GetAvailableServers()),其存在DelegateCommand内驻留到我自己的视图模型运行:
public ICommand GetAvailableServersFromViewModel
{
get
{
return new DelegateCommand
{
CanExecuteFunc =() => true,
CommandAction =() =>
{
Task.Run(() => utilsIp.GetAvailableServers());
}
};
}
}
与我的实现的问题是UI在扫描时滞后,这很容易通过我的UI中的加载微调器看到。那么代码远不是最好的,我知道我错了某个地方。
在最大负载下将调试器暂停10次。每次查看UI线程堆栈。什么代码正在运行?这是滞后于你的用户界面的代码。 – usr 2015-02-09 22:51:12
我尝试过,但我没有找到明确的东西给我。我还尝试删除与百分比更新相关的任何UI逻辑,并且仅使用Task.Run((=)=> utilsIp.GetAvailableServers())离开代码;我再次遇到滞后。看起来问题是当等待client.GetStringAsync抛出一个异常,(我有大量的异常导致在扫描过程中99%的IP根本不存在),但我不知道为什么我有这种行为,因为这应该在不同的线程上工作...... – jded 2015-02-15 16:03:22
将URL更改为始终指向有效的端点。落后了吗?如果是的话,错误与这个问题有关。 – usr 2015-02-15 19:38:49