Инди FTP, большие файлы и маршрутизаторы NAT

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

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

Много программ отправляют команду NOOP периодически для поддержания канала команды, даже если это не часть стандартной спецификации FTP. Мой вопрос: как я делаю это? Я отправляю команду NOOP в событии OnWork? Это вызывает сопутствующий ущерб в некотором роде, как, я должен обработать некоторый ответ? Как я лучше всего решаю эту проблему?

7
задан vcldeveloper 19 April 2010 в 09:06
поделиться

1 ответ

Мы используем несколько подходов, чтобы справиться с этим: (1) включить пакеты поддержки активности TCP / IP на канале управления во время передачи и (2 ) корректно восстанавливаются после разрыва соединения, (3) поддерживают возобновление прерванных передач.

Многие FTP-клиенты отправляют NOOP, пока все неактивно, но я не знаю, отправляют ли они их во время передачи данных, потому что в этом случае вам нужно будет обрабатывать ответы, а многие серверы не будут отправлять их обратно до завершения передачи данных.

  1. 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; 
     
  2. Для корректного восстановления, если файл был успешно передан, просто подключитесь в конце заново и введите SIZE или СПИСОК для получения размера файла. Если они совпадают, значит, файл был успешно перенесен, и вам больше ничего делать не нужно. Если сервер поддерживает это, вы также можете отправить команду XCRC , чтобы получить значение CRC, чтобы вы могли сравнить его с локальным файлом.

  3. Если вы хотите быть действительно надежным, вы также можете проверить TIdFTP.CanResume . Если он установлен, сервер поддерживает команду REST , поэтому вы можете продолжить передачу с того места, где остановились, передав true параметру AResume в TIdFTP.Get / Put .

3
ответ дан 7 December 2019 в 16:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: