SFTP put получает неожиданный EOF для файла 50M при первой передаче дня

538
P. Heggie

Я выполняю SFTP, чтобы поместить файл в новый внешний клиент. У нас есть около 10 других клиентов, некоторые внутренние и некоторые внешние, которые мы загружаем без проблем. Этот новый клиент находится с нами в VPN (некоторые другие наши клиенты также находятся у нас с VPN, но не со всеми) и отвечает на команду пут EOF после передачи около 40 М файла размером 50 МБ. Это произошло на 10 из последних 14 казней.

За исключением двух случаев, EOF принимается один раз, при первом запуске дня, около 5:00 утра. Когда я снова запускаю SFTP через несколько минут, команда put работает и передается полный файл. Для остальной части дня это работает также. В том же исполнении мы также отправляем два других файла, один из которых равен 1М, а другой - 10М. Мой скрипт сортирует список файлов по размеру файла, поэтому меньшие файлы отправляются первыми. Это все в рамках одной и той же связи. Мой скрипт сначала подключается, отправляет пароль и проверяет, что он принят, выполняет изменение каталога, команду ls и команду df. Затем в скрипте есть цикл, чтобы поместить все файлы в списке. Первые два файла помещаются успешно, а затем третий, но он завершается неудачно с EOF.

В двух случаях, которые являются исключением, я получил EOF со второй попытки, а затем пут успешно завершился с третьей попытки. в целом, это было 10 из последних 14 пробежек. Остальные четыре пробежки сработали с первого раза (дня). Эта работа выполняется примерно в одно и то же время (с 4:50 до 5:15). Я поговорил с клиентом и немного изменил время, чтобы обойти интервалы, в течение которых они запускают процесс мониторинга папок. Но это не имеет значения.

Мы работаем с OpenSSH_6.0p1 в AIX 7.1, а они работают с OpenSSH_7.4p1 в CentOS Linux 7.4. Дважды я пытался запустить SFTP из командной строки с подробным параметром (-vvv), и пут работал в этих двух случаях. Я обновлю свой скрипт, чтобы каким-то образом записывать подробный вывод в файл журнала. Но я получил этот EOF как в сценарии, так и в командной строке, поэтому я не думаю, что это сценарий. И я могу сначала отправить два других файла, так что проблема не только с первым отправленным файлом. И это не просто проблема с размером файла, даже если он не работает только с файлом 50M, потому что он отлично работает через несколько минут.

Поэтому некоторые из моих вопросов - что может вызвать EOF для операции put? Я нашел спецификацию RFC версии 2 для SFTP и не вижу упоминания EOF для операций put, только для операций get. Может ли быть какой-то фоновый процесс в CentOS Linux, который может вызвать EOF при передаче большого файла? Передача занимает около 25 секунд. Может ли это быть сетевой ошибкой? Может ли качество сети сначала быть плохим, но через несколько минут автоматически перейти на более высокий уровень качества? Клиент 2700 миль. Спасибо за любые комментарии. Питер

ОБНОВЛЕНИЕ: поставщик отправил мне свой журнал отладки SFTP, и я не вижу какой-либо конкретной причины:

28745 debug1: request 786: write "/upload/X_Y_Z_file_20180315040147.txt" (handle 0) off 25329664 len 32768 28745 debug3: request 786: sent status 0 28745 sent status Success 28745 debug1: request 787: write "/upload/X_Y_Z_file_20180315040147.txt" (handle 0) off 25362432 len 32768 28745 debug3: request 787: sent status 0 28745 sent status Success 28745 debug1: request 788: write "/upload/X_Y_Z_file_20180315040147.txt" (handle 0) off 25395200 len 32768 28745 debug3: request 788: sent status 0 28745 sent status Success 28745 debug1: read eof 28745 forced close "/upload/X_Y_Z_file_20180315040147.txt" bytes read 0 written 25427968 28745 session closed for local user abc from [1.2.3.4] 

Изменить: я не думаю, что мой сценарий является проблемой (но я знаю, как это звучит), потому что я получаю ту же проблему, независимо от того, использую ли я сценарий или запускаю команду SFTP из командной строки. Сценарий использует EXPECT для перехвата ответа SFTP, который является одним из «100%», или EOF или TIMEOUT. Я приложу сценарий, как только выясню, как это сделать.

Редактировать: вот скрипт для sftp:

#! /usr/bin/ksh # The following line is seen as a continuecomment by Tcl\ exec $QUOVADX_INSTALL_DIR/integrator/bin/hcitcl "$0" $  # subroutines first proc gts {} {  set tt [clock format [clock seconds] -format {%y/%m/%d %H:%M:%S} ] set ms [format %03d [expr {[clock clicks -milliseconds] % 1000}]] return $tt.$ms  }  # proc to write to debug file proc debugw { global debugfile set fh [open $debugfile a] ; puts $fh "$msg" ; close $fh }   set frdir [lindex $argv 0] set lfile [lindex $argv 1] set todir [lindex $argv 2] set site [lindex $argv 3]  set debug $::env(cldebug) set parmfile $::env(clparmfile) set module "sftp_put_list"  # get debugfilename if {$debug}  if {$debug}  if {$debug}   # get SFTP connection parms from parmfile using $site as key set hfile [open $parmfile r] ; set data [read $hfile] ; close $hfile set lList [split $data "\n"] ; set pos [lsearch -regexp $lList "^key_sftp_$site"] lassign [split [lindex $lList $pos] " "] key port url pass if {$debug > 1}   # url with vertical bar means the first part is the userid and second is the url set userList [split "$url" "|"] ; lassign $userList user url if {$debug}  set ullen [llength $userList] if {$debug}    log_user 0  # start/spawn the sftp process - either simple user url or separate user  if {[llength $userList] eq 1} { set hname "$user" spawn /usr/bin/sftp -o Port=$port -o ConnectTimeout=60 $user  if {$debug}  } else { set hname "$url" spawn /usr/bin/sftp -o Port=$port -o ConnectTimeout=60 -o User=$user $url if {$debug}  }  set pass_word_prompt "*?assword:*" set sftp_prompt "*?ftp>" set timeout 300  set sftp_put_timeout 1000 set prompt_timeout 300  #-------------------------------------------------------------- # first, wait for the password prompt - if a password is required! #-------------------------------------------------------------- if {$pass ne "#"} { expect { eof { echo "sftp EOF waiting for password prompt|NA" if {$debug}  exit 8 } "$pass_word_prompt" { if {$debug}  } timeout { echo "sftp timeout waiting for password prompt|NA" if {$debug}  exit 8 } }  set timeout $prompt_timeout send "$pass\r" expect { eof { echo "sftp EOF waiting for command prompt after entering password|NA" if {$debug}  exit 8 } "$sftp_prompt" { if {$debug}  } timeout { echo "sftp timeout after $prompt_timeout seconds waiting for command prompt after entering password|NA" if {$debug}  exit 8 } } } else { expect { eof { echo "sftp EOF waiting for command prompt after logging on|NA" if {$debug}  exit 8 } "$sftp_prompt" { if {$debug}  } timeout { echo "sftp timeout after $prompt_timeout seconds waiting for command prompt after logging on|NA" if {$debug}  exit 8 } }  }  #-------------------------------------------------------------- # lcd to local directory from where you will send the file(s) #-------------------------------------------------------------- set timeout $prompt_timeout send "lcd $frdir\r" expect { eof { echo "sftp EOF waiting for command prompt after entering LCD|NA" if {$debug}  exit 8 } "$sftp_prompt" { if {$debug}  } timeout { echo "sftp timeout after $prompt_timeout seconds waiting for command prompt after entering LCD|NA" if {$debug}  exit 8 } }  #-------------------------------------------------------------- # cd to remote directory where you will put the file(s) #-------------------------------------------------------------- set timeout $prompt_timeout send "cd $todir\r" expect { eof { echo "sftp EOF waiting for command prompt after entering CD command|NA" if {$debug}  exit 8 } "No such file or directory" { echo "remote directory $todir not found or not accessible|NA" if {$debug}  exit 8 } "$sftp_prompt" { if {$debug}  } timeout { echo "sftp timeout after $prompt_timeout seconds waiting for prompt after entering CD command|NA" if {$debug}  exit 8 } }   #-------------------------------------------------------------- # print working directory #-------------------------------------------------------------- set timeout $prompt_timeout send "pwd\r" expect { eof { echo "sftp EOF waiting for command prompt after entering pwd command|NA" if {$debug}  exit 8 } "$sftp_prompt" { set response $expect_out(0,string) set rwd [lindex [split "$response" ":"] 1]  set rwd [lindex [split "$rwd" "\r" ] 0] if {$debug}  if {$debug}  } timeout { echo "sftp timeout after $prompt_timeout seconds waiting for prompt after entering pwd command|NA" if {$debug}  exit 8 } }  #-------------------------------------------------------------- # directory list #-------------------------------------------------------------- set timeout $prompt_timeout send "ls -l\r" expect { eof { echo "sftp EOF waiting for command prompt after entering dir command|NA" if {$debug}  exit 8 } "$sftp_prompt" { set response $expect_out(0,string) set dir [lrange [split "$response" "\r"] 1 end-1]  set dir [string map {\{ "" \} ""} "$dir"] set dir [string trim "$dir"] if {$debug}  if {$debug}  } timeout { echo "sftp timeout after $prompt_timeout seconds waiting for prompt after entering dir command|NA" if {$debug}  exit 8 } }  #------------------------------------------------ # loop through list of files - put each file to remote sftp server #------------------------------------------------ set hfile [open $lfile r] ; set data [read $hfile] ; close $hfile set flist [string map {"\n" " "} "$data" ] ; set flist [string trim "$flist"]  set flist [split $flist " "] ; set nfiles [llength $flist] if {$debug}   set ct 0 while {$ct < $nfiles} { set nextfile [lindex $flist $ct] if {$debug}  set dct [expr $ct + 1]  set timeout $sftp_put_timeout send "put $nextfile\r" expect { eof { set response $expect_out(0,string) echo "sftp EOF waiting for command prompt after entering put command|$nextfile" if {$debug}  if {$debug}  if {$debug}  exit 8 } "100%*$sftp_prompt" { if {$debug}  if {$debug}  } timeout { echo "sftp timeout after $sftp_put_timeout seconds waiting for prompt after entering put command|$nextfile" if {$debug}  exit 8 } }  incr ct }  #-------------------------------------------------------------- # post transfer directory list #-------------------------------------------------------------- set timeout $prompt_timeout send "ls -l\r" expect { eof { echo "sftp EOF waiting for command prompt after entering dir command|NA" if {$debug}  exit 8 } "$sftp_prompt" { set response $expect_out(0,string) set dir [lrange [split "$response" "\r"] 1 end-1]  set dir [string map {\{ "" \} ""} "$dir"] set dir [string trim "$dir"] if {$debug}  if {$debug}  } timeout { echo "sftp timeout after $prompt_timeout seconds waiting for prompt after entering dir command|NA" if {$debug}  exit 8 } }  #--------------------------------------------------------- # sftp checks for spawn EOF and will terminate prematurely # unless you add extra expect command #--------------------------------------------------------- set timeout $prompt_timeout send "quit\r" expect { eof { if {$debug}  exit 0 } "$sftp_prompt" { echo "unexpected sftp prompt after entering QUIT command - should be EOF|NA" if {$debug}  exit 2 } timeout { echo "sftp timeout after $prompt_timeout seconds waiting for EOF after QUIT command|NA" if {$debug}  exit 8 } }  exit 0 
2

0 ответов на вопрос

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