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 线程再次冻结。 这就是您进行异步编程的方式。一路异步。