常常使用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 )