При разработке интеграций в 1С часто возникает ситуация, когда код подключения к FTP-серверу успешно отрабатывает во внешней обработке в режиме клиента, но при запуске в регламентном или фоновом задании на сервере зависает либо падает с ошибкой инициализации конструктора FTPСоединение. Разберем детально причины такого поведения и способы корректной настройки сетевого обмена на стороне сервера 1С:Предприятия.
Самая распространенная причина долгого зависания вызовов конструктора или методов работы с файлами — использование активного режима передачи данных по умолчанию. В активном режиме FTP-сервер пытается самостоятельно открыть входящее TCP-соединение к клиенту. Если сервер 1С находится за NAT, маршрутизатором или межсетевым экраном, входящие пакеты блокируются, и процесс ожидает ответа до истечения системного таймаута TCP.
Для решения проблемы переведем соединение в пассивный режим (Passive Mode), передав значение Истина в 6-й параметр конструктора FTPСоединение. В этом режиме все соединения (как командные, так и для передачи данных) инициируются самой платформой 1С наружу.
// Создание подключения с явным указанием пассивного режима и таймаута
СерверFTP = "ftp.example.com";
ПортFTP = 21;
Логин = "ftp_user";
Пароль = "ftp_password";
Прокси = Неопределено;
ПассивныйРежим = Истина;
Таймаут = 30; // таймаут в секундах
Попытка
Соединение = Новый FTPСоединение(
СерверFTP,
ПортFTP,
Логин,
Пароль,
Прокси,
ПассивныйРежим,
Таймаут
);
Исключение
ЗаписьЖурналаРегистрации(
"FTP.ОшибкаПодключения",
УровеньЖурналаРегистрации.Ошибка,,,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())
);
Соединение = Неопределено;
КонецПопытки;
Начиная с версии платформы 8.3.9, в конструкторе FTPСоединение появились параметры для работы с шифрованием SSL/TLS. По умолчанию платформа может инициировать попытку защищенного подключения. Если FTP-сервер не поддерживает FTPS или мобильный/корпоративный канал связи фильтрует попытки TLS-рукопожатия на 21 порту, вызов конструктора завершается ошибкой или зависает.
Если сервер работает по обычному незащищенному протоколу FTP, отключим шифрование принудительно с помощью перечисления УровеньИспользованияЗащищенногоСоединенияFTP:
// Отключение принудительного защищенного соединения для обычного FTP
УровеньЗащиты = УровеньИспользованияЗащищенногоСоединенияFTP.НеИспользовать;
Соединение = Новый FTPСоединение(
СерверFTP,
ПортFTP,
Логин,
Пароль,
Прокси,
ПассивныйРежим,
Таймаут,
УровеньЗащиты
);
Важное различие протоколов: Объект FTPСоединение поддерживает классический протокол FTP и FTPS (FTP поверх SSL/TLS). Протокол SFTP (SSH File Transfer Protocol, работающий через порт 22) данным объектом платформы не поддерживается. Попытка подключиться к SFTP-хосту через FTPСоединение приведет к ошибке протокола или зависанию соединения по таймауту.
Регламентные и фоновые задания выполняются не под учетной записью пользователя операционной системы, запустившего клиентское приложение, а в контексте системной службы сервера 1С (обычно usr1cv8 в ОС Windows или Linux). Проанализируем различия в сетевом окружении:
usr1cv8 нет пользовательских настроек Internet Explorer/браузера. Если в сети используется прокси-сервер или, наоборот, прямое подключение в обход прокси, рекомендуется передавать в конструктор явно инициализированный объект ИнтернетПрокси (например, Новый ИнтернетПрокси(Ложь) при прямом доступе).Рассмотрим надежный шаблон функции для скачивания файлов из каталога FTP с последующей очисткой удаленного ресурса, корректной обработкой исключений и освобождением сетевых ресурсов:
Процедура ВыполнитьОбменСФТП() Экспорт
ХостFTP = "ftp.myserver.ru";
ПортFTP = 21;
ЛогинFTP = "sync_user";
ПарольFTP = "SecretPass123";
ПутьНаФТП = "/incoming/";
ЛокальныйКаталог = "C:\Exchange\In\";
Попытка
// Инициализируем соединение: пассивный режим, таймаут 20 секунд, без SSL
ФТП = Новый FTPСоединение(
ХостFTP,
ПортFTP,
ЛогинFTP,
ПарольFTP,
Новый ИнтернетПрокси(Ложь),
Истина,
20,
УровеньИспользованияЗащищенногоСоединенияFTP.НеИспользовать
);
Исключение
ЗаписьЖурналаРегистрации(
"Обмен FTP",
УровеньЖурналаРегистрации.Ошибка,,,
"Не удалось установить связь с FTP: " + ОписаниеОшибки()
);
Возврат;
КонецПопытки;
Попытка
// Получаем список файлов по маске
МассивФайлов = ФТП.НайтиФайлы(ПутьНаФТП, "*.xml");
Для Каждого ТекущийФайл Из МассивФайлов Цикл
Если ТекущийФайл.ЭтоФайл() Тогда
ЛокальныйФайл = ЛокальныйКаталог + ТекущийФайл.Имя;
// Загружаем файл на локальный диск сервера
ФТП.Получить(ТекущийФайл.ПолноеИмя, ЛокальныйФайл);
// Удаляем обработанный файл с FTP
ФТП.Удалить(ПутьНаФТП, ТекущийФайл.Имя);
КонецЕсли;
КонецЦикла;
Исключение
ЗаписьЖурналаРегистрации(
"Обмен FTP",
УровеньЖурналаРегистрации.Ошибка,,,
"Ошибка при обработке файлов: " + ОписаниеОшибки()
);
КонецПопытки;
// Освобождаем объект для немедленного закрытия сокета
ФТП = Неопределено;
КонецПроцедуры
Рекомендация по освобождению сокетов: Поскольку объект FTPСоединение не содержит явного метода закрытия, сокет удерживается до сборки мусора. Обязательно присваивайте переменной значение Неопределено после завершения цикла обмена, чтобы избежать исчерпания пула свободных исходящих портов операционной системы.