2013-03-17 93 views
2

我试图找到所有的FTP服务器接受一个给定的ips集上的匿名连接。异步FTP调用永不结束

基本上,我得到我想检查的IP,然后在它们每个上尝试一个ListDirectory。如果我没有例外,ftp存在并且可以访问。

我正在使用异步方法来验证IP,这会使事情变得更快。但是,我需要等到所有异步调用返回。要做到这一点,我一直在异步调用我的数的计数器,的问题是这样的计数器永远不会为0。

我的代码如下:

通过IP地址进行迭代:

static int waitingOn; 
public static IEnumerable<Uri> GetFtps() 
{ 
    var result = new LinkedList<Uri>(); 
    waitingOn = 0; 

    IPNetwork ipn = IPNetwork.Parse("192.168.72.0/21"); 
    IPAddressCollection ips = IPNetwork.ListIPAddress(ipn); 

    foreach(var ip in ips) 
    { 
     VerifyFtpAsync(ip, result); 
    } 

    while (waitingOn > 0) 
    { 
     Console.WriteLine(waitingOn); 
     System.Threading.Thread.Sleep(1000); 
    } 

    return result; 
} 

,并验证每个IP:

public async static void VerifyFtpAsync(IPAddress ip, LinkedList<Uri> ftps) 
{ 
    ++waitingOn; 
    try 
    { 
     Uri serverUri = new Uri("ftp://" + ip); 
     FtpWebRequest request = (FtpWebRequest)WebRequest.Create(serverUri); 
     request.Method = WebRequestMethods.Ftp.ListDirectoryDetails; 
     request.Timeout = 10000; 
     request.Credentials = new NetworkCredential("anonymous", "[email protected]"); 

     FtpWebResponse response = (FtpWebResponse) await request.GetResponseAsync(); 

     // If we got this far, YAY! 
     ftps.AddLast(serverUri); 
    } 
    catch (WebException) 
    { 
    } 
    --waitingOn; 
} 
+1

您的代码似乎缺少您设置hsip的部分。此外,您在致电VerifyFtpAsync时缺少此项功能。也许有一个VerifyFtpAsync包装函数。 – 2013-03-17 01:58:30

+0

忘记改变这些,我试图将Uri添加到HashSet(hsip)来查看哪些调用没有返回,但是最后我的HashSet有4个空元素(而不是waitingOn == 4)。 – roim 2013-03-17 02:01:20

+0

我会首先评论你有没有等待的那一行,看看它是否完成。对不起,我对这个没什么帮助。 – 2013-03-17 02:08:25

回答

1

首先,你不应该使用async void,除非你正在写一个事件处理程序。

接下来,如果您的async方法可能并行运行(例如,如果此代码在控制台应用程序中运行),则确实需要保护变量和集合免受多线程访问。就你而言,这听起来像你可能想要使用Task.WhenAll而不是手动计数器,并删除共享集合。

public async static Task<Uri> VerifyFtpAsync(IPAddress ip) 
{ 
    try 
    { 
    ... 
    return serverUri; 
    } 
    catch (WebException) 
    { 
    return null; 
    } 
} 

... 

var ipTasks = ips.Select(ip => VerifyFtpAsync(ip)); 
var allResults = await Task.WhenAll(ipTasks); 
var result = allResults.Where(url => url != null).ToArray(); 
+0

我仍然不明白为什么这解决了我的问题,是不是所有的异步调用都应该在单线程中执行? (我知道等待的东西可以在另一个线程中运行,但它不访问我的任何变量)。 哦,并在你的回应中为Linq迷人+1 +1 – roim 2013-03-17 03:28:29

+1

@rOim这取决于你如何打电话给它。如果它来自控制台应用程序或“ThreadPool”线程,则不会在单个线程上执行延续(除非您非常幸运)。 – svick 2013-03-17 09:35:34

+0

此解决方案有时仍然挂起。我修改了ipTasks线进行调试: var ipTasks = ips.Select(ip => VerifyFtpAsync(ip).ContinueWith(t => {Console.WriteLine(Interlocked.Increment(ref scanning)+“/”+ total); return t.Result;})); 有时输出在2047/2048停止 – roim 2013-03-17 22:03:46