2016-10-24 9 views
2

Я использую SFTP-клиент Paramiko для загрузки файла с удаленного сервера клиенту (т. Е. Операция получения)
Файл, который нужно передать, немного огромен ~ 1 ГБ.
Так что я хотел бы получить операцию до таймаута, если время больше 10 секунд.Установка timelimit для sftp.get() модуля Paramiko

Но установка значения таймаута для подключения не работает. Похоже, что это таймаут для создания SSH-соединения, а не таймаута для всего ssh-соединения.

ssh = paramiko.SSHClient() 
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 
ssh.connect(host, username=username, password=password, timeout=10.0) 
sftp = ssh.open_sftp() 
start_time = time.time() 
sftp.get(local_path,remote_path) 
elapsed_time = time.time()-start_time 
print elapsed_time 
sftp.close() 

Я также попытался установить значение тайм-аута для канала, но он не работает слишком

sftp.get_channel.settimeout(10.0) 

Но этот таймаут снова только для операций чтения/записи

Существует аналогичный вопрос Timeout in paramiko (python), но у него есть только ответ на таймаут при создании SSH-соединения

Обновление 1

После замечаний @Martin я реализовал функцию обратного вызова, которая проверяет временной предел для операции GET из SFTP:

import paramiko 
import time 

Class TimeLimitExceeded(Exception): 
    pass 

timelimit = 10 
start_time = time.time() 

def _timer(): 
    elapsed_time = time.time()-start_time 
    if elapsed_time > timelimit: 
     raise TimeLimitExceeded 

ssh = paramiko.SSHClient() 
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 
ssh.connect(host, username=username, password=password, timeout=10.0) 
sftp = ssh.open_sftp() 
try: 
    sftp.get(local_path,remote_path,_timer) 
except TimeLimitExceeded: 
    print "The operation took too much time to complete" 
sftp.close() 

Но время, за исключением исключения много, код блокировки где-то. Я погрузился в исходный код Парамико и нашел виновника позади этого метода _close(self,async=False)sftp_file.py Любая помощь, чтобы обойти это?

Update 2

Попытка закрыть канал сам, если TimeLimit превышен. Тогда исключение продувают утешать как prefetch реализован отдельный демон нить

File "/scratch/divjaisw/python2.7/lib/python2.7/threading.py", line 801, in __bootstrap_inner 
    self.run() 
    File "/scratch/divjaisw/python2.7/lib/python2.7/threading.py", line 754, in run 
    self.__target(*self.__args, **self.__kwargs) 
    File "/scratch/divjaisw/python_virtual/lib/python2.7/site-packages/paramiko/sftp_file.py", line 488, in _prefetch_thread 
    num = self.sftp._async_request(self, CMD_READ, self.handle, long(offset), int(length)) 
    File "/scratch/divjaisw/python_virtual/lib/python2.7/site-packages/paramiko/sftp_client.py", line 754, in _async_request 
    self._send_packet(t, msg) 
    File "/scratch/divjaisw/python_virtual/lib/python2.7/site-packages/paramiko/sftp.py", line 170, in _send_packet 
    self._write_all(out) 
    File "/scratch/divjaisw/python_virtual/lib/python2.7/site-packages/paramiko/sftp.py", line 133, in _write_all 
    n = self.sock.send(out) 
    File "/scratch/divjaisw/python_virtual/lib/python2.7/site-packages/paramiko/channel.py", line 715, in send 
    return self._send(s, m) 
    File "/scratch/divjaisw/python_virtual/lib/python2.7/site-packages/paramiko/channel.py", line 1081, in _send 
    raise socket.error('Socket is closed') 
error: Socket is closed 
+0

Он блокируется бесконечно? Или временно?Где именно в '_close' он блокируется? На вызов '_finish_responses'? –

+0

Он временно блокирует. Фактически он вообще не блокирует, но попадает в цикл while внутри '_read_response (self, waitfor = None)', здесь waitfor = 6781, который вызывается '_request' и который сам вызывается by '_close' с' async = False' –

+0

Я добавил возможное объяснение в свой ответ. Хотя полный столбец поможет лучше проанализировать проблему. –

ответ

1

То, что вы просите, это на самом деле не тайм-аут. Термин «тайм-аут» используется для предела ожидания ответа.

Но ваш сервер не перестает отвечать. Связь активна.


Что вы просите, это скорее предел для продолжительности операции. Вы вряд ли можете ожидать, что это будет легко реализовано для вас. Это скорее конкретное требование. Вы должны реализовать его самостоятельно.

Вы можете использовать callback аргумент get method:

def get(self, remotepath, localpath, callback=None): 

В обратном вызове, проверить длительность передачи и выбросить исключение, если срок истекает.

Это не отменяет передачу немедленно. Чтобы оптимизировать производительность передачи, Paramiko ставит на сервер до 100 запросов на чтение (см. condition in the sftp_file._write). Как только вы попытаетесь отменить передачу, Paramiko должен ждать (до 100) ответов на эти запросы, чтобы очистить очередь.

 Смежные вопросы

  • Нет связанных вопросов^_^