Как FTP постоянно входящие файлы - PullRequest
3 голосов
/ 27 мая 2011

Хорошо, вот ситуация ... У меня есть приложение, которое генерирует около 8 файлов в секунду.Каждый файл 19-24kb.Это создает около 10-11 МБ в минуту.Этот вопрос не о том, как ftp, потому что у меня уже есть это решение ... Вопрос больше о том, как не отставать от потока данных (в большинстве случаев только 2 Мб полосы пропускания, если я не еду на сайт клиента).это большая труба).Мне все равно, если ftp займет больше времени для передачи, чем скорость потока, но я хочу знать, есть ли у кого-нибудь идея о том, как пакетировать файлы, чтобы переместить их, чтобы, когда процесс ftp завершился, он удалил только те файлы, которые он передала затем перейти к следующей партии.Вот что я думал:

Многопоточное приложение, первый поток запускает приложение, второй поток - это таймер, который создает текстовый файл каждые 'N' минут со всеми файлами, созданными за этот промежуток времени.StreamRead файл и переместить текстовые файлы в другое место (возможно, создать временную папку), а затем ftp эти файлы, затем удалить файлы, папку и текстовый файл ... в то же время, больше текстовых файлов пишутся и темппапки создаются.Это звучит выполнимо?Я приму любые предложения, которые кто-нибудь посоветует, просто ищет самый быстрый и самый надежный путь.

Пожалуйста, не просите видеть код, нет никаких причин видеть его, учитывая, что мы работаем с гипотетиками.

Ответы [ 7 ]

4 голосов
/ 27 мая 2011

Я бы создал службу и добавил входящие файлы в параллельную коллекцию, используя FileSystemWatcher, System.Threading.Timer или оба (FileSystemWatcher может пропустить файлы, если его буфер переполнен, поэтому рекомендуется выбрать таймер для выбора любые пропущенные файлы). Когда файлы приходят, я помещаю их в отдельную папку и обрабатываю их с помощью задач .NET 4.0. Затем я сделаю любую необходимую постобработку в продолжении шагов к исходным задачам. У вас могут быть шаги продолжения, которые обрабатывают любые ошибки и различные шаги продолжения, которые происходят в случае успеха. Каждая из этих задач будет раскручивать поток в пуле потоков и будет управляться за вас.

Вот пример из http://msdn.microsoft.com/en-us/library/dd997415.aspx задачи продолжения OnlyOnFaults. У вас может быть вторая задача продолжения, которая будет выполняться только в случае успеха.

var task1 = Task.Factory.StartNew(() =>
{
    throw new MyCustomException("Task1 faulted.");
})
.ContinueWith((t) =>
    {
        Console.WriteLine("I have observed a {0}",
            t.Exception.InnerException.GetType().Name);
    },
    TaskContinuationOptions.OnlyOnFaulted);
1 голос
/ 27 мая 2011

Я работал над чем-то похожим на моей старой работе.Я бы извлек файлы внешнего процесса в определенную папку.Вот алгоритм, которому я следовал:

  1. Запустите FileSystemWatcher в исходном каталоге, куда файлы будут выгружены
  2. Когда новый файл найден, обработайте ALL файлы из каталога в порядке возрастания даты.(в вашем случае ftp файл)
  3. Как только файл обработан, я перемещаю его в Обработанный каталог (в вашем случае вы можете удалить их)

Что следует учитывать:

  1. Сколько открытых соединений / потоков обработки ftp я могу иметь
  2. FileSystemWatcher может и будет вызывать событие при обработке другого файла.Как с этим справиться / отправить в соответствующую ветку
1 голос
/ 27 мая 2011

Не зная по-настоящему подробностей о том, почему вам нужно хранить всю работу в одном приложении и справляться со сложностью потоков, можно поспорить, что часть, которая генерирует файлы, и часть, которая передает файлы по FTP, в отдельных приложениях.

Разделение ответственности. Убедитесь, что каждое приложение выполняет только одну работу и выполняет ее правильно и быстро.

Один Serivce или приложение (рабочий стол / веб, который когда-либо) генерирует файлы.

Другая служба, которая просматривает папку и перемещает любые входящие файлы во временный архиватор, делает то, что ей нужно, FTP и удаляет.

Видя, что я не знаю ваши настройки и откуда вы берете контент для ваших файлов, запись в одном приложении может быть лучшим выбором именно так, как вы предлагаете.

В основном, чтобы ответить на ваш вопрос. Да, это звучит реально, что вы хотите сделать. Как вы реализуете это, и что вам нравится в реализации, зависит от вас.

Если вы застряли где-то во время реализации, не стесняйтесь сообщать о любых проблемах в новой угрозе с некоторыми примерами кода о том, как реализована конкретная функция и с какой проблемой вы столкнулись.

До тех пор, гипотетически, любой подход, который, по вашему мнению, способен управлять тем, что вам нужно для достижения, является совершенно действительным.

EDIT

Видя, что вы заявили, что у вас уже есть приложение, которое генерирует готовые файлы, и у вас уже есть решение, которое для FTP означает использование двух отдельных приложений, звучит более правдоподобно.

Все, что вам нужно, - это обернуть службу вокруг решения FTP и счастливых дней. Нет необходимости вмешиваться в исходное приложение, которое генерирует файлы, если оно уже работает.

Зачем рисковать, если вы не добавите в него функцию fTP, и у вас нет выбора.

0 голосов
/ 21 июня 2011

Как владелец FTP-сервера в этой ситуации, я бы также попросил вас найти способ как можно дольше оставаться в сети.

Вход / выключение входа часто более «дорого» (с точки зрения вычислений, блокировки конфигурации и т. Д.), Чем передача отдельных файлов.

0 голосов
/ 28 мая 2011

Я бы настроил цепочку потоков, используя BlockingCollections.

Один поток производителей читает файлы, используя таймер или FileSystemWatcher и т. Д., И сохраняет их в BlockingCollection.Он также сохраняет файлы в списке, чтобы гарантировать, что они добавляются только один раз.

var availableFiles = new BlockingCollection<string>();
var processedFiles = new BlockingCollection<string>();
var newFiles = new HashSet<string>();

...
lock (newFiles) {
    foreach (var file in Directory.GetFiles())
        if (!newFiles.Contains(file)) {
            availableFiles.Add(file);
            newFiles.Add(file);
        }
}

Один или несколько потоков ftp отправляют файлы и помещают их в обработанную коллекцию

foreach (var file in availableFiles.GetConsumingEnumerable()) {
   SendFileOverFtp(file);
   processedFiles.Add(file);
}

Один поток очищает обработанные файлы

foreach (var file in processedFiles.GetConsumingEnumerable()) {
    lock (newFiles) {
       File.Delete(file);
       newFiles.Remove(file);
    }
}

Другая альтернатива состоит в том, чтобы производящий поток также считывал файлы в память и удалял их.В этом случае вы можете пропустить последний этап и коллекцию newFiles

0 голосов
/ 27 мая 2011
  1. Запуск таймера, который срабатывает один раз в секунду.
  2. В обработчике истекшего времени таймера остановите таймер.
  3. Получите список всех файлов во входящем каталоге.
  4. Попробуйте открыть каждый файл исключительно.Это предотвращает чтение файла, в который все еще выполняется запись.
  5. Скопируйте каждый файл в промежуточный каталог и удалите его из входящего каталога.
  6. После перемещения всех файловв своем списке отправьте файлы в промежуточный каталог по FTP.
  7. После того, как вы сделали файлы FTP, удалите их из промежуточного каталога.
  8. Запустите таймер.

Обработчик истекшего таймера запускается для вас в пуле потоков, и вам нужно любое более интересное управление потоками.Поскольку ваше основное ограничение - пропускная способность вашего FTP, нет никаких преимуществ делать что-либо еще с другими потоками, пока файлы не будут загружены.

Этот подход обеспечивает защиту в случае сбоя системы.Файлы, которые находятся в промежуточном каталоге и которые не отправлены, извлекаются во время следующего цикла.То же самое относится и к файлам во входящем каталоге.

Если принимающая сторона FTP может обрабатывать заархивированные файлы, вы повысите пропускную способность, сжав содержимое промежуточного каталога и отправив его как один файл.

0 голосов
/ 27 мая 2011

Вам нужно вставить очередь между производителем файлов и потребителем (хост FTP), чтобы иметь возможность буферизовать файлы, если производитель работает слишком быстро.Это требует некоторой формы многопоточности или даже нескольких процессов.

Вы предлагаете решение, в котором очередь является файловой системой, и это вполне возможно, но во многих случаях не идеально.Вы должны получить право блокировки, чтобы избежать передачи наполовину заполненных или пустых файлов и т. Д. Если вы решите использовать файловую систему, то, по моему опыту, FileSystemWatcher не может использоваться для этой цели.Использование таймера для запуска задачи, скажем, каждую секунду для получения новых файлов, гораздо более надежно.

Другие технологии очереди могут представлять собой очередь в памяти (но тогда вам нужно подумать о том, как обрабатывать сбои),личная очередь сообщений Microsoft или очередь брокера SQL Server.Лучшее решение во многом зависит от ваших требований.

FTP не является на самом деле транзакционным, и вы можете решить использовать очередь, которая не транзакционна (MSMQ и SQL Server Broker являются транзакционными), но вам все равно следует попытатьсяСоздайте свои приложения на основе концепции транзакции, в которой файл создается, ставится в очередь и доставляется.Если он не может быть доставлен, он остается в очереди, и доставка повторяется позже.Если он не может быть поставлен в очередь, производитель должен повторить попытку поставить его в очередь и т. Д. Вам не нужна ситуация, когда файл никогда не доставляется или доставляется дважды.

Из вашего вопроса неясно, как вы собираетесьиспользуйте FTP, но я бы посоветовал вам использовать коммерческую библиотеку с открытым исходным кодом, чтобы иметь возможность напрямую использовать FTP из вашего приложения вместо того, чтобы выдавать ftp.exe.Это позволит вашему приложению вести себя разумно, поддерживая соединение FTP открытым, чтобы избежать чрезмерных повторных подключений и т. Д.

Вам также следует подумать о том, как справиться с ситуацией, когда очередь становится слишком большой.Одним из вариантов может быть остановка производителя до тех пор, пока размер очереди не уменьшится ниже порогового значения.

...