我具有如下功能,可连接端口不断变化的FTP
private int FindWorkingPort(int from, int to)
{
for (int port = from; port <= to; port++)
{
try
{
new FtpClient(_host, port).Connect(); // Instant on correct port, very slow on wrong port
return port;
}
catch { }
}
throw new Exception("None of the port is working");
}
第一次尝试正确时,它是即时的。否则,每次尝试可能需要10秒钟。您可以想象如果正确的是最后一个。
有什么办法可以使其同时尝试所有可能的端口? (我是多线程菜鸟)
编辑:
我正在使用的FluentFTP确实有.ConnectAsync()
答案 0 :(得分:0)
这不是最好的,但可行的解决方案:
var tasks = Enumerable.Range(from, to - from).ToList().Select(port => {
try
{
return new FtpClient(_host, port).ConnectAsync().ContinueWith(_ => (int?)port);
}
catch
{
return Task.FromResult((int?)null);
}
});
var foundPort = (await Task.WhenAll(tasks)).FirstOrDefault(p => p != null);
基本上,您将创建要检查的所有端口的列表,并为每个端口启动一个任务。您要等到它们全部异步完成,然后得到第一个不是null
的东西。所有任务将并行运行,但是await Task.WhenAll
将等待所有任务完成,这意味着它将始终等待〜10秒(根据您的问题,检查不正确的端口通常花费〜10秒)。
使用Task.WhenAny
可能可以改善这一点,但是当其他任务抛出异常时,返回正确的端口很困难。
答案 1 :(得分:0)
这是另一种方法。第一个有效任务完成后,应立即返回:
public async Task<int> FindWorkingPortAsync(int from, int to)
{
var wrapper = new TaskCompletionSource<int>();
var tasks = Enumerable.Range(from, to - from).ToList().Select(port =>
{
return new FtpClient(_host, port).ConnectAsync().ContinueWith(t => {
try
{
if(!wrapper.Task.IsCompleted && !t.IsFaulted && !t.IsCanceled)
wrapper.SetResult(port);
return t;
}
catch
{
return Task.FromResult(-1);
}
});
}).ToList();
return await wrapper.Task;
}
让我知道它是否有效。我使用HttpClient
而不是FtpClient
进行了测试。
答案 2 :(得分:-2)
您可以尝试使用多个线程同时连接到所有端口,但是随着更多线程的启动,性能将下降。我建议您尝试使用Task。
这里是Task和Event的示例。这不是完全解决方案,但是您将获得要点。您可能必须更改代码结构。
using System;
using System.Threading.Tasks;
public class Program
{
public class MyEventArgs : EventArgs
{
public int port {get; set; }
public MyEventArgs(int port)
{
this.port = port;
}
}
delegate void OpenPort(object sender, MyEventArgs e);
event OpenPort OnOpen;
int from = 10, to = 20;
int Connected = 16;
public static void Main()
{
var obj = new Program();
// here you register your method ShowPort for OnOpen event.
obj.OnOpen += new OpenPort(ShowPort);
for(int i = obj.from; i < obj.to; i++) {
obj.CheckPort(obj, i);
}
}
private async void CheckPort(Program obj, int i)
{
await CheckPortTask(obj, i);
}
private Task CheckPortTask(Program obj, int i)
{
return Task.Run(() => {
if(i == obj.Connected)
{
obj.OnOpen(this, new MyEventArgs(i));
}
});
}
// This method will be called after connecting.
public static void ShowPort(Object p, MyEventArgs args)
{
Console.WriteLine(args.port);
}
}
如果要尝试使用线程,则用以下代码替换上面代码中的Task.Run块:
new Thread(()=>{
if(i == obj.w)
{
// this raises the event and calls the ShowPort method.
obj.OnOpen(obj, new MyEventArgs(i));
}
})).Start();