python获取交互式ssh shell的方法


Posted in Python onFebruary 14, 2019

更新,最近在学unix环境编程,了解一下进程的创建过程,用最原始的方式实现了一个ssh命令的执行。

#coding=utf8
 
'''
用python实现了一个简单的shell,了解进程创建
类unix 环境下 fork和exec 两个系统调用完成进程的创建
'''
 
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位的二进制数字,高8位为退出状态码,低8位为程序结束系统信号的编号
 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模块。

经查找,从paramiko的源码包demos目录下,可以看到交互式shell的实现,就是那个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置为空,否则粘贴多字节或者按方向键的时候显示不正确
 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系统调用唤醒引发的系统中断,忽略中断重新调用解决。
    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、当读取键盘输入时,方向键会有问题,因为按一次方向键会产生3个字节数据,我的理解是按键一次会被select捕捉一次标准输入有变化,但是我每次只处理1个字节的数据,其他的数据会存放在输入缓冲区中,等待下次按键的时候一起发过去。这就导致了本来3个字节才能完整定义一个方向键的行为,但是我只发过去一个字节,所以终端并不知道我要干什么。所以没有变化,当下次触发按键,才会把上一次的信息完整发过去,看起来就是按一下方向键有延迟。多字节的粘贴也是一个原理。解决办法是将输入缓冲区置为0,这样就没有缓冲,有多少发过去多少,这样就不会有那种显示的延迟问题了。

2、终端大小适应。paramiko.channel会创建一个pty(伪终端),有个默认的大小(width=80, height=24),所以登录过去会发现能显示的区域很小,并且是固定的。编辑vim的时候尤其痛苦。channel中有resize_pty方法,但是需要获取到当前终端的大小。经查找,当终端窗口发生变化时,系统会给前台进程组发送SIGWINCH信号,也就是当进程收到该信号时,获取一下当前size,然后再同步到pty中,那pty中的进程等于也感受到了窗口变化,也会收到SIGWINCH信号。

3、读写‘慢'设备(包括pipe,终端设备,网络连接等)。读时,数据不存在,需要等待;写时,缓冲区满或其他原因,需要等待。ssh通道属于这一类的。本来进程因为网络没有通信,select调用为阻塞中的状态,但是当终端窗口大小变化,接收到SIGWINCH信号被唤醒。此时select会出现异常,触发系统中断(4, 'Interrupted system call'),但是这种情况只会出现一次,当重新调用select方法又会恢复正常。所以捕获到select异常后重新进行select可以解决该问题。

以上这篇python获取交互式ssh shell的方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python连接sql server乱码的解决方法
Jan 28 Python
Python脚本判断 Linux 是否运行在虚拟机上
Apr 25 Python
使用Python程序抓取新浪在国内的所有IP的教程
May 04 Python
Python3连接MySQL(pymysql)模拟转账实现代码
May 24 Python
Python2.7 实现引入自己写的类方法
Apr 29 Python
python实现C4.5决策树算法
Aug 29 Python
Pyqt5 实现跳转界面并关闭当前界面的方法
Jun 19 Python
python3在同一行内输入n个数并用列表保存的例子
Jul 20 Python
pycharm修改file type方式
Nov 19 Python
python 中不同包 类 方法 之间的调用详解
Mar 09 Python
python+opencv实现车道线检测
Feb 19 Python
TensorFlow的自动求导原理分析
May 26 Python
对python多线程SSH登录并发脚本详解
Feb 14 #Python
Python Selenium 之关闭窗口close与quit的方法
Feb 13 #Python
python 实现selenium断言和验证的方法
Feb 13 #Python
使用Python自动化破解自定义字体混淆信息的方法实例
Feb 13 #Python
python selenium执行所有测试用例并生成报告的方法
Feb 13 #Python
对python_discover方法遍历所有执行的用例详解
Feb 13 #Python
django2.0扩展用户字段示例
Feb 13 #Python
You might like
十天学会php之第八天
2006/10/09 PHP
php模拟asp中的XmlHttpRequest实现http请求的代码
2011/03/24 PHP
PC端微信扫码支付成功之后自动跳转php版代码
2017/07/07 PHP
基于PHP实现栈数据结构和括号匹配算法示例
2017/08/10 PHP
学习YUI.Ext 第七天--关于View&amp;JSONView
2007/03/10 Javascript
通过jquery还原含有rowspan、colspan的table的实现方法
2012/02/10 Javascript
javascript面向对象之访问对象属性的两种方式分析
2015/01/13 Javascript
jQuery使用append在html元素后同时添加多项内容的方法
2015/03/26 Javascript
JavaScript返回当前会话cookie全部键值对照的方法
2015/04/03 Javascript
浅谈JS中json数据的处理
2016/06/30 Javascript
深入学习js瀑布流布局
2016/10/14 Javascript
JS中Map和ForEach的区别
2018/02/05 Javascript
使用veloticy-ui生成文字动画效果
2018/02/08 Javascript
Node.js 多进程处理CPU密集任务的实现
2019/05/26 Javascript
解决vue-cli项目开发运行时内存暴涨卡死电脑问题
2019/10/29 Javascript
浅谈js中的attributes和Attribute的用法与区别
2020/07/16 Javascript
Vue Object.defineProperty及ProxyVue实现双向数据绑定
2020/09/02 Javascript
js canvas实现俄罗斯方块
2020/10/11 Javascript
python pdb调试方法分享
2014/01/21 Python
python 使用sys.stdin和fileinput读入标准输入的方法
2018/10/17 Python
python 多维高斯分布数据生成方式
2019/12/09 Python
Django查询优化及ajax编码格式原理解析
2020/03/25 Python
Django设置Postgresql的操作
2020/05/14 Python
python实现取余操作的简单实例
2020/08/16 Python
详解Python Celery和RabbitMQ实战教程
2021/01/20 Python
HTML5 解析规则分析
2009/08/14 HTML / CSS
奥地利网上书店:Weltbild
2017/07/14 全球购物
澳大利亚领先的在线机械五金、园艺和存储专家:Edisons
2018/03/24 全球购物
STUBHUB日本:购买和出售全球活动门票
2018/07/01 全球购物
英国和世界各地预订便宜的酒店:LateRooms.com
2019/05/05 全球购物
Puma印度官网:德国运动品牌
2019/10/06 全球购物
法国亚马逊官方网站:Amazon.fr
2020/12/19 全球购物
一道写SQL的面试题和答案
2013/11/19 面试题
法人代表授权委托书
2014/04/08 职场文书
群众路线问题查摆对照检查材料
2014/10/04 职场文书
幼儿园教师培训心得体会
2016/01/21 职场文书