python獲取交互式ssh shell的方法
更新,最近在學(xué)unix環(huán)境編程,了解一下進(jìn)程的創(chuàng)建過(guò)程,用最原始的方式實(shí)現(xiàn)了一個(gè)ssh命令的執(zhí)行。
#coding=utf8
'''
用python實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的shell,了解進(jìn)程創(chuàng)建
類unix 環(huán)境下 fork和exec 兩個(gè)系統(tǒng)調(diào)用完成進(jìn)程的創(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 # 返回值是一個(gè)16位的二進(jìn)制數(shù)字,高8位為退出狀態(tài)碼,低8位為程序結(jié)束系統(tǒng)信號(hào)的編號(hào)
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)
最近在做一個(gè)項(xiàng)目,需要在客戶端集成一個(gè)交互式ssh功能,大概就是客戶端跟服務(wù)器申請(qǐng)個(gè)可用的機(jī)器,服務(wù)端返回個(gè)ip,端口,密碼, 然后客戶端就可以直接登錄到機(jī)器上操做了。該程序基于paramiko模塊。
經(jīng)查找,從paramiko的源碼包demos目錄下,可以看到交互式shell的實(shí)現(xiàn),就是那個(gè)demo.py。但是用起來(lái)有些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) # 終端大小改變時(shí),修改pty終端大小
stdin = os.fdopen(sys.stdin.fileno(), 'r', 0) # stdin buff置為空,否則粘貼多字節(jié)或者按方向鍵的時(shí)候顯示不正確
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信號(hào)將休眠的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)
#關(guān)閉連接
channel.close()
ssh.close()
interactive.py代碼中主要修復(fù)了幾個(gè)問(wèn)題:
1、當(dāng)讀取鍵盤輸入時(shí),方向鍵會(huì)有問(wèn)題,因?yàn)榘匆淮畏较蜴I會(huì)產(chǎn)生3個(gè)字節(jié)數(shù)據(jù),我的理解是按鍵一次會(huì)被select捕捉一次標(biāo)準(zhǔn)輸入有變化,但是我每次只處理1個(gè)字節(jié)的數(shù)據(jù),其他的數(shù)據(jù)會(huì)存放在輸入緩沖區(qū)中,等待下次按鍵的時(shí)候一起發(fā)過(guò)去。這就導(dǎo)致了本來(lái)3個(gè)字節(jié)才能完整定義一個(gè)方向鍵的行為,但是我只發(fā)過(guò)去一個(gè)字節(jié),所以終端并不知道我要干什么。所以沒(méi)有變化,當(dāng)下次觸發(fā)按鍵,才會(huì)把上一次的信息完整發(fā)過(guò)去,看起來(lái)就是按一下方向鍵有延遲。多字節(jié)的粘貼也是一個(gè)原理。解決辦法是將輸入緩沖區(qū)置為0,這樣就沒(méi)有緩沖,有多少發(fā)過(guò)去多少,這樣就不會(huì)有那種顯示的延遲問(wèn)題了。
2、終端大小適應(yīng)。paramiko.channel會(huì)創(chuàng)建一個(gè)pty(偽終端),有個(gè)默認(rèn)的大?。╳idth=80, height=24),所以登錄過(guò)去會(huì)發(fā)現(xiàn)能顯示的區(qū)域很小,并且是固定的。編輯vim的時(shí)候尤其痛苦。channel中有resize_pty方法,但是需要獲取到當(dāng)前終端的大小。經(jīng)查找,當(dāng)終端窗口發(fā)生變化時(shí),系統(tǒng)會(huì)給前臺(tái)進(jìn)程組發(fā)送SIGWINCH信號(hào),也就是當(dāng)進(jìn)程收到該信號(hào)時(shí),獲取一下當(dāng)前size,然后再同步到pty中,那pty中的進(jìn)程等于也感受到了窗口變化,也會(huì)收到SIGWINCH信號(hào)。
3、讀寫‘慢'設(shè)備(包括pipe,終端設(shè)備,網(wǎng)絡(luò)連接等)。讀時(shí),數(shù)據(jù)不存在,需要等待;寫時(shí),緩沖區(qū)滿或其他原因,需要等待。ssh通道屬于這一類的。本來(lái)進(jìn)程因?yàn)榫W(wǎng)絡(luò)沒(méi)有通信,select調(diào)用為阻塞中的狀態(tài),但是當(dāng)終端窗口大小變化,接收到SIGWINCH信號(hào)被喚醒。此時(shí)select會(huì)出現(xiàn)異常,觸發(fā)系統(tǒng)中斷(4, 'Interrupted system call'),但是這種情況只會(huì)出現(xiàn)一次,當(dāng)重新調(diào)用select方法又會(huì)恢復(fù)正常。所以捕獲到select異常后重新進(jìn)行select可以解決該問(wèn)題。
以上這篇python獲取交互式ssh shell的方法就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- python SSH模塊登錄,遠(yuǎn)程機(jī)執(zhí)行shell命令實(shí)例解析
- python通過(guò)ssh-powershell監(jiān)控windows的方法
- 解決Python paramiko 模塊遠(yuǎn)程執(zhí)行ssh 命令 nohup 不生效的問(wèn)題
- Python基于模塊Paramiko實(shí)現(xiàn)SSHv2協(xié)議
- python實(shí)現(xiàn)ssh及sftp功能(實(shí)例代碼)
- python使用paramiko實(shí)現(xiàn)ssh的功能詳解
- 使用 Python ssh 遠(yuǎn)程登陸服務(wù)器的最佳方案
- python ssh 執(zhí)行shell命令的示例
相關(guān)文章
Pycharm配置autopep8實(shí)現(xiàn)流程解析
這篇文章主要介紹了Pycharm配置autopep8實(shí)現(xiàn)流程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11
Python如何使用Eel和HTML開發(fā)桌面應(yīng)用
這篇文章主要介紹了Python使用Eel和HTML開發(fā)桌面應(yīng)用問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01
Python圖像處理庫(kù)PIL中圖像格式轉(zhuǎn)換的實(shí)現(xiàn)
這篇文章主要介紹了Python圖像處理庫(kù)PIL中圖像格式轉(zhuǎn)換的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02
使用Python制作讀單詞視頻的實(shí)現(xiàn)代碼
我們經(jīng)常在B站或其他視頻網(wǎng)站上看到那種逐條讀單詞的視頻,但他們的視頻多多少少和我們的預(yù)期都不太一致,然而,網(wǎng)上很難找到和自己需求符合的視頻,所以本文給大家介紹了使用Python制作讀單詞視頻的實(shí)現(xiàn),需要的朋友可以參考下2024-04-04
python爬蟲 正則表達(dá)式使用技巧及爬取個(gè)人博客的實(shí)例講解
下面小編就為大家?guī)?lái)一篇python爬蟲 正則表達(dá)式使用技巧及爬取個(gè)人博客的實(shí)例講解。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-10-10
python之基數(shù)排序的實(shí)現(xiàn)
這篇文章主要介紹了python之基數(shù)排序的實(shí)現(xiàn),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07
Python隨機(jī)數(shù)random模塊使用指南
本文給大家分享的是Python隨機(jī)數(shù)random模塊的幾個(gè)常用的方法,非常的簡(jiǎn)單,小伙伴們喜歡的話,后續(xù)繼續(xù)深入探討2016-09-09

