python ssh工具paramiko的修改

常常使用paramiko工具對幾百臺設備進行管理。主要是天天到上邊取文件過來,做爲備份。服務器

今天發現程序運行了10個小時尚未結束,就上去看一個究竟。session


查看日誌,發如今取一臺服務器上的文件時卡在那裏了。本身手動ssh登陸上去,執行了一個ls命令就卡住了,ssh

原來是這個服務器的硬盤出問題了。怪不得取不到文件。socket


可是想一想,程序應該是在一段時間內讀取不到數據就超時退出的阿,怎麼會卡在那裏呢。找到執行命令的那段工具

sin, sout, serr = ssh.exec_command('tar -zc0 /data/important-file.txt')this

這條語句是過去了,可是後邊日誌

sout.read(10240)繼承

這條語句一直卡在那裏,不動彈了。看來sout是沒有設置超時的。查查paramiko的源代碼吧。找了一下,在client.py中ip

    def exec_command(self, command, bufsize=-1)rem

        chan = self._transport.open_session()

        chan.exec_command(command)

        stdin = chan.makefile('wb', bufsize)

        stdout = chan.makefile('rb', bufsize)

        stderr = chan.makefile_stderr('rb', bufsize)

        return stdin, stdout, stderr


那個stout就是chan.makefile()出來的。繼續看makefile

    def makefile(self, *params):

        return ChannelFile(*([self] + list(params)))

這裏看不出什麼,重點在ChannelFile的read方法上,查到read方法。ChannelFile繼承了BufferedFile,由於文檔中寫道,這個

ChannelFile是個file-like的object, 因此_read方法應該是實際read去調用的方法。看代碼

    def _read(self, size):

        return self.channel.recv(size)

很簡單,是channel的recv方法(這個channel就是makefile時的第一個參數self,也就是transport.open_session()出來的那個chan)。

仍是回到Channel去,recv方法

def recv(self, nbytes):

        try:

            out = self.in_buffer.read(nbytes, self.timeout)

        except PipeTimeout, e:

            raise socket.timeout()


        ack = self._check_add_window(len(out))

        # no need to hold the channel lock when sending this

        if ack > 0:

            m = Message()

            m.add_byte(chr(MSG_CHANNEL_WINDOW_ADJUST))

            m.add_int(self.remote_chanid)

            m.add_int(ack)

            self.transport._send_user_message(m)


        return out

從黑體的部分能夠看出,原來recv是能夠設置timeout的,只是paramiko默認的沒有設置而已。好了,把timeout設置上,就OK。

修改了一下paramiko代碼,運行了一下,程序也沒有卡在那個地方,除了那臺出問題的服務器,其他的都正常取到。

修改辦法以下,修改client.py的exec_command方法以下

    def exec_command(self, command, bufsize=-1, timeout = None ):

        chan = self._transport.open_session()

        if timeout is not None:

            chan.settimeout(timeout)

        chan.exec_command(command)

        stdin = chan.makefile('wb', bufsize)

        stdout = chan.makefile('rb', bufsize)

        stderr = chan.makefile_stderr('rb', bufsize)

        return stdin, stdout, stderr

黑體部分爲增長的部分。而在調用的地方,改成

sin, sout, serr = ssh.exec_command('tar -zc0 /data/important-file.txt', timeout = 20.0 )

相關文章
相關標籤/搜索