Загрузите несколько файлов по FTP, используя одно соединение в. NET Core - PullRequest
1 голос
/ 29 мая 2020

Я пытаюсь загрузить несколько файлов в память, используя только одно открытое соединение.

Я знаю из этой документации: https://docs.microsoft.com/en-us/dotnet/api/system.net.ftpwebrequest.keepalive - что FtpWebRequest по умолчанию KeepAlive равно true .

если соединение с сервером не должно быть разорвано; в противном случае - ложь. Значение по умолчанию - истина.

Я создал этот фрагмент кода:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;

namespace ConsoleApp23
{
    class Program
    {

        static void Main(string[] args)
        {
            String[] files = FTPListTree("ftp://server.com", "user", "password");

            for (int i = 0; i <= files.Count() - 1; i++)
            {
                string path = files[i].ToString();
                var request = (FtpWebRequest)WebRequest.Create(path);
                request.Method = WebRequestMethods.Ftp.DownloadFile;
                request.Credentials = new NetworkCredential("user", "password");
                request.Timeout = 100000;
                request.KeepAlive = true;
                request.ConnectionGroupName = "DownloadFilesGroup";
                request.ServicePoint.ConnectionLimit = 8;

                using (var response = (FtpWebResponse)request.GetResponse())
                {
                    using (var stream = response.GetResponseStream())
                    {
                        var ms = new MemoryStream();
                        stream.CopyTo(ms);
                        var a = ms.ToArray();
                        string ss = Encoding.UTF8.GetString(a);
                        Console.WriteLine(ss);
                    }
                }
            }
        }

        public static String[] FTPListTree(String ftpUri, String user, String pass)
        {

            try
            {
                List<String> files = new List<String>();
                Queue<String> folders = new Queue<String>();
                folders.Enqueue(ftpUri);

                while (folders.Count > 0)
                {
                    String fld = folders.Dequeue();
                    List<String> newFiles = new List<String>();

                    FtpWebRequest ftp = (FtpWebRequest)FtpWebRequest.Create(fld);
                    ftp.Timeout = 20000;
                    ftp.Credentials = new NetworkCredential(user, pass);
                    ftp.Method = WebRequestMethods.Ftp.ListDirectory;

                    using (StreamReader resp = new StreamReader(ftp.GetResponse().GetResponseStream()))
                    {
                        String line = resp.ReadLine();
                        while (line != null)
                        {
                            newFiles.Add(line.Trim());
                            line = resp.ReadLine();
                        }
                    }

                    ftp = (FtpWebRequest)FtpWebRequest.Create(fld);
                    ftp.Timeout = 20000;
                    ftp.Credentials = new NetworkCredential(user, pass);
                    ftp.Method = WebRequestMethods.Ftp.ListDirectory;

                    using (StreamReader resp = new StreamReader(ftp.GetResponse().GetResponseStream()))
                    {
                        String line = resp.ReadLine();
                        while (line != null)
                        {
                            if (!Path.HasExtension(line))
                            {
                                String dir = newFiles.First(x => line.EndsWith(x));
                                newFiles.Remove(dir);
                                folders.Enqueue(fld + dir + "/");
                            }
                            line = resp.ReadLine();
                        }
                    }
                    files.AddRange(from f in newFiles select fld + f);
                }
                return files.ToArray();
            }
            catch (Exception e)
            {
                throw;
            }
        }
    }
}

Это правильный способ удаления? Кажется, я не могу найти никакой документации о том, что удаление response или потока ответов закроет управляющее соединение, что keepalive будет оставаться открытым.

Есть ли способ записать это при запуске это, чтобы я мог видеть вызовы FTP? У меня нет доступа к FTP-серверу.

ОБНОВЛЕНИЕ

Я действительно протестировал это с помощью тестового FTP и приведенного выше кода, хотя он имеет KeepAlive=true, он использует новое соединение при каждом запросе. Я создал Po C с Fluent API: https://github.com/robinrodricks/FluentFTP/blob/master/FluentFTP.CSharpExamples/DownloadManyFiles.cs, который делает это правильно: подключается один раз и загружает файлы. Было такое ощущение, что так и было с FtpWebRequest. Я не понимаю KeepAlive и что он делает. Возможно, он повторно использует TCP-соединение, что само по себе хорошо, но оно использует TCP-соединение для входа в систему по каждому запросу.

Кто-нибудь знает, возможно ли это даже с FtpWebRequest, без входа в систему каждый новый запрос, например Fluent FTP API? Я что-то упустил?

Пример журнала FTP можно увидеть здесь FTP log

FTP - это FileZilla Server 0.9.60 beta.

1 Ответ

1 голос
/ 31 мая 2020

Похоже, что повторное использование FTP-соединения не было реализовано в. NET Core: https://github.com/dotnet/runtime/issues/23256

И поскольку *WebRequest API фактически устарел, вероятно, никогда не будет.


С. NET framework, он работает, как ожидалось:
Несколько файлов FTP в C# без восстановления соединения

...