您好,登錄后才能下訂單哦!
這篇文章主要介紹了python如何獲取交互式ssh shell,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
1、簡單易用,與C/C++、Java、C# 等傳統(tǒng)語言相比,Python對代碼格式的要求沒有那么嚴格;2、Python屬于開源的,所有人都可以看到源代碼,并且可以被移植在許多平臺上使用;3、Python面向?qū)ο?,能夠支持面向過程編程,也支持面向?qū)ο缶幊蹋?、Python是一種解釋性語言,Python寫的程序不需要編譯成二進制代碼,可以直接從源代碼運行程序;5、Python功能強大,擁有的模塊眾多,基本能夠?qū)崿F(xiàn)所有的常見功能。
用最原始的方式實現(xiàn)了一個ssh命令的執(zhí)行。
#coding=utf8 ''' 用python實現(xiàn)了一個簡單的shell,了解進程創(chuàng)建 類unix 環(huán)境下 fork和exec 兩個系統(tǒng)調(diào)用完成進程的創(chuàng)建 ''' import sys, os def myspawn(cmdline): argv = cmdline.split() if len(argv) == 0: return program_file = argv[0] pid = os.fork() if pid < 0: sys.stderr.write("fork error") elif pid == 0: # child os.execvp(program_file, argv) sys.stderr.write("cannot exec: "+ cmdline) sys.exit(127) # parent pid, status = os.waitpid(pid, 0) ret = status >> 8 # 返回值是一個16位的二進制數(shù)字,高8位為退出狀態(tài)碼,低8位為程序結(jié)束系統(tǒng)信號的編號 signal_num = status & 0x0F sys.stdout.write("ret: %s, signal: %s\n" % (ret, signal_num)) return ret def ssh(host, user, port=22, password=None): if password: sys.stdout.write("password is: '%s' , plz paste it into ssh\n" % (password)) cmdline = "ssh %s@%s -p %s " % (user, host, port) ret = myspawn(cmdline) if __name__ == "__main__": host = '' user = '' password = '' ssh(host, user, password=password)
最近在做一個項目,需要在客戶端集成一個交互式ssh功能,大概就是客戶端跟服務器申請個可用的機器,服務端返回個ip,端口,密碼, 然后客戶端就可以直接登錄到機器上操做了。該程序基于paramiko模塊。
經(jīng)查找,從paramiko的源碼包demos目錄下,可以看到交互式shell的實現(xiàn),就是那個demo.py。但是用起來有些bug,于是我給修改了一下interactive.py(我把windows的代碼刪掉了,剩下的只能在linux下用)。代碼如下:
#coding=utf-8 import socket import sys import os import termios import tty import fcntl import signal import struct import select now_channel = None def interactive_shell(chan): posix_shell(chan) def ioctl_GWINSZ(fd): try: cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ,'aaaa')) except: return return cr def getTerminalSize(): cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2) return int(cr[1]), int(cr[0]) def resize_pty(signum=0, frame=0): width, height = getTerminalSize() if now_channel is not None: now_channel.resize_pty(width=width, height=height) def posix_shell(chan): global now_channel now_channel = chan resize_pty() signal.signal(signal.SIGWINCH, resize_pty) # 終端大小改變時,修改pty終端大小 stdin = os.fdopen(sys.stdin.fileno(), 'r', 0) # stdin buff置為空,否則粘貼多字節(jié)或者按方向鍵的時候顯示不正確 fd = stdin.fileno() oldtty = termios.tcgetattr(fd) newtty = termios.tcgetattr(fd) newtty[3] = newtty[3] | termios.ICANON try: termios.tcsetattr(fd, termios.TCSANOW, newtty) tty.setraw(fd) tty.setcbreak(fd) chan.settimeout(0.0) while True: try: r, w, e = select.select([chan, stdin], [], []) except: # 解決SIGWINCH信號將休眠的select系統(tǒng)調(diào)用喚醒引發(fā)的系統(tǒng)中斷,忽略中斷重新調(diào)用解決。 continue if chan in r: try: x = chan.recv(1024) if len(x) == 0: print 'rn*** EOFrn', break sys.stdout.write(x) sys.stdout.flush() except socket.timeout: pass if stdin in r: x = stdin.read(1) if len(x) == 0: break chan.send(x) finally: termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty)
使用示例:
#coding=utf8 import paramiko import interactive #記錄日志 paramiko.util.log_to_file('/tmp/aaa') #建立ssh連接 ssh=paramiko.SSHClient() ssh.load_system_host_keys() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect('192.168.1.11',port=22,username='hahaha',password='********',compress=True) #建立交互式shell連接 channel=ssh.invoke_shell() #建立交互式管道 interactive.interactive_shell(channel) #關閉連接 channel.close() ssh.close()
interactive.py代碼中主要修復了幾個問題:
1、當讀取鍵盤輸入時,方向鍵會有問題,因為按一次方向鍵會產(chǎn)生3個字節(jié)數(shù)據(jù),我的理解是按鍵一次會被select捕捉一次標準輸入有變化,但是我每次只處理1個字節(jié)的數(shù)據(jù),其他的數(shù)據(jù)會存放在輸入緩沖區(qū)中,等待下次按鍵的時候一起發(fā)過去。這就導致了本來3個字節(jié)才能完整定義一個方向鍵的行為,但是我只發(fā)過去一個字節(jié),所以終端并不知道我要干什么。所以沒有變化,當下次觸發(fā)按鍵,才會把上一次的信息完整發(fā)過去,看起來就是按一下方向鍵有延遲。多字節(jié)的粘貼也是一個原理。解決辦法是將輸入緩沖區(qū)置為0,這樣就沒有緩沖,有多少發(fā)過去多少,這樣就不會有那種顯示的延遲問題了。
2、終端大小適應。paramiko.channel會創(chuàng)建一個pty(偽終端),有個默認的大?。╳idth=80, height=24),所以登錄過去會發(fā)現(xiàn)能顯示的區(qū)域很小,并且是固定的。編輯vim的時候尤其痛苦。channel中有resize_pty方法,但是需要獲取到當前終端的大小。經(jīng)查找,當終端窗口發(fā)生變化時,系統(tǒng)會給前臺進程組發(fā)送SIGWINCH信號,也就是當進程收到該信號時,獲取一下當前size,然后再同步到pty中,那pty中的進程等于也感受到了窗口變化,也會收到SIGWINCH信號。
3、讀寫‘慢'設備(包括pipe,終端設備,網(wǎng)絡連接等)。讀時,數(shù)據(jù)不存在,需要等待;寫時,緩沖區(qū)滿或其他原因,需要等待。ssh通道屬于這一類的。本來進程因為網(wǎng)絡沒有通信,select調(diào)用為阻塞中的狀態(tài),但是當終端窗口大小變化,接收到SIGWINCH信號被喚醒。此時select會出現(xiàn)異常,觸發(fā)系統(tǒng)中斷(4, 'Interrupted system call'),但是這種情況只會出現(xiàn)一次,當重新調(diào)用select方法又會恢復正常。所以捕獲到select異常后重新進行select可以解決該問題。
感謝你能夠認真閱讀完這篇文章,希望小編分享的“python如何獲取交互式ssh shell”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業(yè)資訊頻道,更多相關知識等著你來學習!
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。