Я использовал Инди для файлов передач через FTP уже много лет, но не смог найти удовлетворительное решение для следующей проблемы.
Когда пользователь загружает большой файл позади маршрутизатора, иногда следующее происходит: файл загружается хорошо, но тем временем канал команды разъединяется из-за тайм-аута. Обычно это не делает происходит с прямым подключением к серверу, потому что сервер "знает", что передача происходящий на канале передачи данных. Некоторые маршрутизаторы не знают об этом, хотя и команда канал закрывается.
Много программ отправляют команду NOOP периодически для поддержания канала команды, даже если это не часть стандартной спецификации FTP. Мой вопрос: как я делаю это? Я отправляю команду NOOP в событии OnWork? Это вызывает сопутствующий ущерб в некотором роде, как, я должен обработать некоторый ответ? Как я лучше всего решаю эту проблему?
Мы используем несколько подходов, чтобы справиться с этим: (1) включить пакеты поддержки активности TCP / IP на канале управления во время передачи и (2 ) корректно восстанавливаются после разрыва соединения, (3) поддерживают возобновление прерванных передач.
Многие FTP-клиенты отправляют NOOP, пока все неактивно, но я не знаю, отправляют ли они их во время передачи данных, потому что в этом случае вам нужно будет обрабатывать ответы, а многие серверы не будут отправлять их обратно до завершения передачи данных.
Indy 10.5.8 (Delphi XE2) изначально поддерживает сохранение активности TCP / IP. Просто используйте свойство TIdFTP NATKeepAlive
.
Для предыдущих выпусков назначьте события OnDataChannelCreate / OnDataChannelDestroy:
const
KeepAliveIdle = 2 * SecsPerMin;
KeepAliveInterval = 2 * SecsPerMin;
IOC_VENDOR {= 18000000 долларов США; {1}} SIO_KEEPALIVE_VALS = DWORD (IOC_IN или IOC_VENDOR или 4);
тип
tcp_keepalive = record
onoff: u_long;
keepalivetime: u_long;
keepaliveinterval: u_long;
end;
процедура TFtpConnection.DataChannelCreated (Sender: TObject;
ADataChannel: TIdTCPConnection); {{1 }} var
Socket: TIdSocketHandle;
ka: tcp_keepalive;
Bytes: DWORD;
begin
// Включение / отключение сообщений проверки активности TCP / IP . Это очень маленькие (40-байтовые) пакеты
// и будут отправляться каждые KeepAliveInterval секунды после того, как соединение
// простаивало в течение секунд KeepAliveIdle. В Win9x / NT4 значения idle и timeout
// являются общесистемными и должны быть установлены в реестре; по умолчанию:
// простоя = 2 часа, интервал = 1 секунда.
Socket: = (FIdFTP.IOHandler as TIdIOHandlerSocket).Связывание;
если Win32MajorVersion> = 5, то begin
ka.onoff: = 1;
ka.keepalivetime: = KeepAliveIdle * MSecsPerSec;
ka.keepaliveinterval: = KeepAliveInterval * MSecsPerSec;
WSAIoctl (Socket.Handle, SIO_KEEPALIVE_VALS, @ka, SizeOf (ka), nil, 0, @Bytes,
nil, nil)
end {{1 }} else
Socket.SetSockOpt (Id_SOL_SOCKET, Id_SO_KEEPALIVE, Id_SO_True)
end;
процедура TFtpConnection.DataChannelDestroy (ASender: TObject;
ADataChannel : TIdTCPConnection);
var
Socket: TIdSocketHandle;
begin
Socket: = (FIdFTP.IOHandler as TIdIOHandlerSocket) .Binding;
Socket. SetSockOpt (Id_SOL_SOCKET, Id_SO_KEEPALIVE, Id_SO_False)
end;
Для корректного восстановления, если файл был успешно передан, просто подключитесь в конце заново и введите SIZE или СПИСОК для получения размера файла. Если они совпадают, значит, файл был успешно перенесен, и вам больше ничего делать не нужно. Если сервер поддерживает это, вы также можете отправить команду XCRC , чтобы получить значение CRC, чтобы вы могли сравнить его с локальным файлом.
Если вы хотите быть действительно надежным, вы также можете проверить TIdFTP.CanResume
. Если он установлен, сервер поддерживает команду REST , поэтому вы можете продолжить передачу с того места, где остановились, передав true
параметру AResume
в TIdFTP.Get / Put
.