How to timeout sftp.put() with signal Module or other ? - Python

你说的曾经没有我的故事 提交于 2020-01-24 00:38:12

问题


I would like timeout the function sftp.put(), I have tried with signal Module but the script doesn't die if the upload time is over 10s. I use that to transfer files by ssh (paramiko).

[...]
def handler(signum, frame):
        print 'Signal handler called with signal', signum
        raise IOError("Couldn't upload the fileeeeeeeeeeee!!!!")

[...]
raspi = paramiko.SSHClient()
raspi.set_missing_host_key_policy(paramiko.AutoAddPolicy())
raspi.connect(ip , username= "", password= "" , timeout=10)
sftp = raspi.open_sftp()        

[...]   
signal.signal(signal.SIGALRM, handler)
signal.alarm(10)

sftp.put(source, destination , callback=None, confirm=True)  

signal.alarm(0)
raspi.close()

[...]

Update 1:

I want to abort the transfer if the server stops responding for a while. Actually, my python script check (in loop) any files in a folder, and send it to this remote server. But in the problem here I want to leave this function in the case of the server become inaccessible suddenly during a transfer (ip server changing, no internet anymore,...). But when I simulate a disconnection, the script stays stuck at this function sftp.put anyway...)

Update 2:

When the server goes offline during a transfer, put() seems to be blocked forever. This happens with this line too:

sftp.get_channel().settimeout(xx)

How to do when we lose the Channel?

Update 3 & script goal

Ubuntu 18.04 and paramiko version 2.6.0

Hello, To follow your remarks and questions, I have to give more details about my very Ugly script, sorry about that :)

Actually, I don’t want to have to kill a thread manually and open a new one. For my application I want that the script run totally in autonomous, and if something wrong during the process, it can still go on. For that I use the Python exception handling. Everything does what I want except when the remote server going off during a transfer: The script stays blocked in the put() function, I think inside a loop. Below, the script contains in total 3 functions to timeout this thanks to your help, but apparently nothing can leave this damned sftp.put() ! Do you have some new idea ?

Import […]
[...]

def handler(signum, frame):
        print 'Signal handler called with signal', signum
        raise IOError("Couldn't upload the fileeeeeeeeeeee!!!!")

def check_time(size, file_size):
    global start_time
        if (time.time() - start_time) > 10:
            raise Exception

i = 0
while i == 0:

    try:


        time.sleep(1) # CPU break
        print ("go!")

        #collect ip server
        fichierIplist = open("/home/robert/Documents/iplist.txt", "r")
        file_lines = fichierIplist.readlines()
        fichierIplist.close()
        last_line = file_lines [len (file_lines)-1]
        lastKnowip = last_line

        data = glob.glob("/home/robert/Documents/data/*")   
        items = len(data) 

        if items != 0: 
        time.sleep(60) #anyway
            print("some Files!:)")
            raspi = paramiko.SSHClient()
            raspi.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            raspi.connect(lastKnowip, username= "", password= "" , timeout=10)

            for source in data: #Upload file by file    
                filename = os.path.basename(source) #
                destination = '/home/pi/Documents/pest/'+ filename #p

                sftp = raspi.open_sftp()

                signal.signal(signal.SIGALRM, handler)
                signal.alarm(10)

                sftp.get_channel().settimeout(10)
                start_time = time.time()

                sftp.put(source, destination, callback=check_time)

                sftp.close()    
                signal.alarm(0) 
            raspi.close()

        else:

            print("noFile!")

    except:
        pass

回答1:


If you want to timeout, when the server stops responding:

  • set the timeout argument of SSHClient.connect (your doing that already),
  • and set sftp.get_channel().settimeout as already suggested by @EOhm

If you want to timeout even when the server is responding, but slowly, implement the callback argument to abort the transfer after certain time:

start_time = time.time()

def check_time(size, file_size):
    global start_time
    if (time.time() - start_time) > ...:
        raise Exception

sftp.put(source, destination, callback=check_time)  

Alternatively, you can run the transfer in a separate thread and kill the thread if it takes too long. Ugly but sure solution.




回答2:


Use sftp.get_channel().settimeout(s) for that instead.




回答3:


After trying a lot of things and with your help and advice, I have found a reliable solution for what I wanted. I execute sftp.put in a separate Thread and my script do what I want. Many thanks for your help

Now if the server shuts down during a transfer, after 60 sec, my script goes on using:

[...]
import threading
[...]
th = threading.Thread(target=sftp.put, args=(source,destination))
th.start()                  
h.join(60)
[...]


来源:https://stackoverflow.com/questions/58844902/how-to-timeout-sftp-put-with-signal-module-or-other-python

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!