c#以异步方式ping机器
c# ping machine in async way
我正在开发一个与外部机器通信的遗留应用程序,并且通信是通过文件进行的。基本上机器 A 写一个文件,B 得到它并用另一个文件回复。
目前一切正常,但我有一个代码,每 5 秒调用一次,检查远程目录(写入文件的位置)是否存在。 Tihs 是代码:
private delegate bool DirectoryExistsDelegate(string folder);
public static bool DirectoryExists(string path, int timeout = 2000)
{
Func<bool> func = () => Directory.Exists(path);
Task<bool> task = new Task<bool>(func);
task.Start();
return task.Wait(timeout) && task.Result;
}
上面的方法似乎冻结了 UI,特别是当我们使用网络共享时,例如 \\10.100.100.1\sharedFolder
所以我想在尝试访问之前 ping 主机:
private static IPStatus PingStatus;
public static async void PingIP(string IPaddress, int timeout = 2000)
{
// Verifica indirizzo IP
if (string.IsNullOrEmpty(IPaddress)) return;
Ping s = new Ping();
PingStatus = await s.SendPingAsync(IPaddress, timeout).ContinueWith(pingTask => pingTask.Result.Status);
}
private delegate bool DirectoryExistsDelegate(string folder);
public static bool DirectoryExists(string path, int timeout = 2000)
{
if (path.StartsWith("\"))
{
string[] address = path.Split('\');
PingIP(address[2], timeout);
if (PingStatus != IPStatus.Success) return false;
}
Func<bool> func = () => Directory.Exists(path);
Task<bool> task = new Task<bool>(func);
task.Start();
return task.Wait(timeout) && task.Result;
}
我将主要方法调用为:
if (!Uti.DirectoryExists(PathCom.Value, 5000))
return false;
我不知道这个想法是否正确,但我想在逻辑上是正确的。问题是 PingStatus return 始终为真(第一次调用时),事件服务器不存在,因为第二个似乎工作正常。
如何让 SendPingAsync 等待 ping 结果而不冻结 UI?
所以,您的代码有几个问题:
永远不要做 async void,除了在事件处理程序中:
public static async void PingIP
应该是
public static async Task PingIP
等待您的任务
PingIP(address[2], timeout);
应该是
await PingIP(address[2], timeout);
从任务调用同步代码
从任务调用同步代码不会使您的代码异步。包装在任务中的同步代码仍然是同步代码。您可以将对同步代码的调用包装在 Task.Run
中,以利用线程池,这使得它 'look' 从您的 UI 线程的角度来看是异步的。
Func<bool> func = () => Directory.Exists(path);
Task<bool> task = new Task<bool>(func);
task.Start();
return task.Wait(timeout) && task.Result;
应该是
bool exists = await Task.Run(() => Directory.Exists(path));
或强制超时:
var task = Task.Run(() => Directory.Exists(path));
if (await Task.WhenAny(task, Task.Delay(timeout)) == task) {
// task completed within timeout
} else {
// timeout logic
}
一路异步
看到上面的代码,您可以看到您也应该使函数 DirectoryExists
异步。还有调用 DirectoryExists
的代码。等等等等
永远不要在 Task 上调用 .Result(几乎永远不会)。这将使您的 UI 线程再次冻结。
这就是您进行异步编程的方式。一路异步。
我正在开发一个与外部机器通信的遗留应用程序,并且通信是通过文件进行的。基本上机器 A 写一个文件,B 得到它并用另一个文件回复。 目前一切正常,但我有一个代码,每 5 秒调用一次,检查远程目录(写入文件的位置)是否存在。 Tihs 是代码:
private delegate bool DirectoryExistsDelegate(string folder);
public static bool DirectoryExists(string path, int timeout = 2000)
{
Func<bool> func = () => Directory.Exists(path);
Task<bool> task = new Task<bool>(func);
task.Start();
return task.Wait(timeout) && task.Result;
}
上面的方法似乎冻结了 UI,特别是当我们使用网络共享时,例如 \\10.100.100.1\sharedFolder 所以我想在尝试访问之前 ping 主机:
private static IPStatus PingStatus;
public static async void PingIP(string IPaddress, int timeout = 2000)
{
// Verifica indirizzo IP
if (string.IsNullOrEmpty(IPaddress)) return;
Ping s = new Ping();
PingStatus = await s.SendPingAsync(IPaddress, timeout).ContinueWith(pingTask => pingTask.Result.Status);
}
private delegate bool DirectoryExistsDelegate(string folder);
public static bool DirectoryExists(string path, int timeout = 2000)
{
if (path.StartsWith("\"))
{
string[] address = path.Split('\');
PingIP(address[2], timeout);
if (PingStatus != IPStatus.Success) return false;
}
Func<bool> func = () => Directory.Exists(path);
Task<bool> task = new Task<bool>(func);
task.Start();
return task.Wait(timeout) && task.Result;
}
我将主要方法调用为:
if (!Uti.DirectoryExists(PathCom.Value, 5000))
return false;
我不知道这个想法是否正确,但我想在逻辑上是正确的。问题是 PingStatus return 始终为真(第一次调用时),事件服务器不存在,因为第二个似乎工作正常。 如何让 SendPingAsync 等待 ping 结果而不冻结 UI?
所以,您的代码有几个问题:
永远不要做 async void,除了在事件处理程序中:
public static async void PingIP
应该是
public static async Task PingIP
等待您的任务
PingIP(address[2], timeout);
应该是
await PingIP(address[2], timeout);
从任务调用同步代码
从任务调用同步代码不会使您的代码异步。包装在任务中的同步代码仍然是同步代码。您可以将对同步代码的调用包装在 Task.Run
中,以利用线程池,这使得它 'look' 从您的 UI 线程的角度来看是异步的。
Func<bool> func = () => Directory.Exists(path);
Task<bool> task = new Task<bool>(func);
task.Start();
return task.Wait(timeout) && task.Result;
应该是
bool exists = await Task.Run(() => Directory.Exists(path));
或强制超时:
var task = Task.Run(() => Directory.Exists(path));
if (await Task.WhenAny(task, Task.Delay(timeout)) == task) {
// task completed within timeout
} else {
// timeout logic
}
一路异步
看到上面的代码,您可以看到您也应该使函数 DirectoryExists
异步。还有调用 DirectoryExists
的代码。等等等等
永远不要在 Task 上调用 .Result(几乎永远不会)。这将使您的 UI 线程再次冻结。 这就是您进行异步编程的方式。一路异步。