我有一个IP发现方法,我用
TcpClient
测试每个IP地址,当任何IP成功连接时,我在内存中设置WebServerIp
,那就是在我的世界中任务成功完成的时候。有没有办法在我的代码中实现它?或者当任务“成功”时某种取消标记。
这是我的代码:
public async Task<bool> DiscoverDeviceAsync()
{
var ips = GeneralService.GetIPAddress();
PhoneIp = string.Join(",", ips.Select(x => x.ToString()));
await Task.Delay(1000);
var tasks = new List<Task>();
foreach (IPAddress ip in ips)
{
byte[] ipBytes = ip.GetAddressBytes();
for (int i = 0; i <= 254; i++)
{
ipBytes[3] = (byte)i;
IPAddress currentIPAddress = new(ipBytes);
tasks.Add(ScanIPAddress(currentIPAddress, 9431));
}
}
await Task.WhenAny(tasks);
return WebServerIp != "";
}
async Task ScanIPAddress(IPAddress ipAddress, int port)
{
try
{
using TcpClient tcpClient = new()
{
SendTimeout = 100,
ReceiveTimeout = 100,
};
await tcpClient.ConnectAsync(ipAddress, port);
WebServerIp = ipAddress.ToString();
}
catch
{
throw new Exception($"No device found at address: {ipAddress}");
}
}
您需要的是一种在工作完成时向主线程和其他线程发出信号的方法。
EventWaitHandle
与 CancellationToken
结合使用
首先我们创建句柄和取消令牌:
var waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset);
var cts = new CancellationTokenSource();
将它们传递给您的方法:
tasks.Add(ScanIPAddress(currentIPAddress, 9431, waitHandle, cts.Token));
然后在方法中设置
WaitHandle
如果连接成功,还要检查取消令牌:
async Task ScanIPAddress(IPAddress ipAddress, int port, EventWaitHandle waitHandle, CancellationToken cancellationToken)
{
try
{
if (cancellationToken.IsCancellationRequested)
{
return;
}
using TcpClient tcpClient = new()
{
SendTimeout = 100,
ReceiveTimeout = 100,
};
await tcpClient.ConnectAsync(ipAddress, port, cancellationToken);
waitHandle.Set();
WebServerIp = ipAddress.ToString();
}
catch
{
throw new Exception($"No device found at address: {ipAddress}");
}
}
此后您可以使用
WaitOne
的EventHandle
方法等待标志被设置。这可能意味着以下两种情况之一:其中一项操作成功,或者全部失败:
// Set wait handle after all tasks are finished, so it doesn't wait forever if none of them are successful
// no await here is intentional as we don't wanna wait for all tasks to complete here.
Task.WhenAll(tasks).ContinueWith(_ => waitHandle.Set());
waitHandle.WaitOne();
cts.Cancel();
return WebServerIp != "";