以异步方式C#ping计算机

时间:2019-06-28 12:58:27

标签: c# asynchronous ping

我正在处理一个与外部计算机进行通信的旧应用程序,并且该通信是通过文件进行的。基本上,机器A写入一个文件,B得到它并用另一个文件答复。 当前,一切正常,但是我有一个每5秒调用一次的代码,该代码检查是否存在远程目录(写入文件的位置)。这是代码:

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在服务器不存在的情况下始终返回True(在第一次调用时),因为第二次似乎工作正常。 如何让SendPingAsync等待ping结果而不冻结UI?

1 个答案:

答案 0 :(得分:2)

因此,您的代码有几处错误:

除了在事件处理程序中,永远不要异步作废:

public static async void PingIP

应该是

public static async Task PingIP

等待任务

PingIP(address[2], timeout);

应该是

await PingIP(address[2], timeout);

从任务中调用同步代码

从Task调用同步代码不会使您的代码异步。封装在Task中的同步代码仍然是同步代码。您可以将对同步代码的调用包装在Task.Run中,以利用线程池,从而从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线程再次冻结。 这就是您进行异步编程的方式。一路异步。