python使用paramiko实现ssh的功能详解


Posted in Python onMarch 06, 2020

个人认为python的paramiko模块是运维人员必学模块之一,其ssh登录功能是旅行居家必备工具。

安装paramiko很简单,pip install paramiko就搞定了,其依赖库会被一并安装。

paramiko的官方站点在这里:http://www.paramiko.org/。有需要深入研究的可以阅读官方文档。

paramiko模块提供了ssh及sft进行远程登录服务器执行命令和上传下载文件的功能。

一、基于用户名和密码的 sshclient 方式登录

# 建立一个sshclient对象
ssh = paramiko.SSHClient()
# 允许将信任的主机自动加入到host_allow 列表,此方法必须放在connect方法的前面
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 调用connect方法连接服务器
ssh.connect(hostname='192.168.2.129', port=22, username='super', password='super')
# 执行命令
stdin, stdout, stderr = ssh.exec_command('df -hl')
# 结果放到stdout中,如果有错误将放到stderr中
print(stdout.read().decode())
# 关闭连接
ssh.close()

二、基于用户名和密码的 transport 方式登录

方法1是传统的连接服务器、执行命令、关闭的一个操作,有时候需要登录上服务器执行多个操作,比如执行命令、上传/下载文件,方法1则无法实现,可以通过如下方式来操作

# 实例化一个transport对象
trans = paramiko.Transport(('192.168.2.129', 22))
# 建立连接
trans.connect(username='super', password='super')

# 将sshclient的对象的transport指定为以上的trans
ssh = paramiko.SSHClient()
ssh._transport = trans
# 执行命令,和传统方法一样
stdin, stdout, stderr = ssh.exec_command('df -hl')
print(stdout.read().decode())

# 关闭连接
trans.close()

三、 基于公钥密钥的 SSHClient 方式登录

# 指定本地的RSA私钥文件,如果建立密钥对时设置的有密码,password为设定的密码,如无不用指定password参数
pkey = paramiko.RSAKey.from_private_key_file('/home/super/.ssh/id_rsa', password='12345')
# 建立连接
ssh = paramiko.SSHClient()
ssh.connect(hostname='192.168.2.129',
      port=22,
      username='super',
      pkey=pkey)
# 执行命令
stdin, stdout, stderr = ssh.exec_command('df -hl')
# 结果放到stdout中,如果有错误将放到stderr中
print(stdout.read().decode())
# 关闭连接
ssh.close()

以上需要确保被访问的服务器对应用户.ssh目录下有authorized_keys文件,也就是将服务器上生成的公钥文件保存为authorized_keys。并将私钥文件作为paramiko的登陆密钥

四、 基于密钥的 Transport 方式登录

# 指定本地的RSA私钥文件,如果建立密钥对时设置的有密码,password为设定的密码,如无不用指定password参数
pkey = paramiko.RSAKey.from_private_key_file('/home/super/.ssh/id_rsa', password='12345')
# 建立连接
trans = paramiko.Transport(('192.168.2.129', 22))
trans.connect(username='super', pkey=pkey)

# 将sshclient的对象的transport指定为以上的trans
ssh = paramiko.SSHClient()
ssh._transport = trans

# 执行命令,和传统方法一样
stdin, stdout, stderr = ssh.exec_command('df -hl')
print(stdout.read().decode())

# 关闭连接
trans.close()

五、传文件 SFTP

# 实例化一个trans对象# 实例化一个transport对象
trans = paramiko.Transport(('192.168.2.129', 22))
# 建立连接
trans.connect(username='super', password='super')

# 实例化一个 sftp对象,指定连接的通道
sftp = paramiko.SFTPClient.from_transport(trans)
# 发送文件
sftp.put(localpath='/tmp/11.txt', remotepath='/tmp/22.txt')
# 下载文件
# sftp.get(remotepath, localpath)
trans.close()

六、 实现输入命令立马返回结果的功能

以上操作都是基本的连接,如果我们想实现一个类似xshell工具的功能,登录以后可以输入命令回车后就返回结果:

import paramiko
import os
import select
import sys

# 建立一个socket
trans = paramiko.Transport(('192.168.2.129', 22))
# 启动一个客户端
trans.start_client()

# 如果使用rsa密钥登录的话
'''
default_key_file = os.path.join(os.environ['HOME'], '.ssh', 'id_rsa')
prikey = paramiko.RSAKey.from_private_key_file(default_key_file)
trans.auth_publickey(username='super', key=prikey)
'''
# 如果使用用户名和密码登录
trans.auth_password(username='super', password='super')
# 打开一个通道
channel = trans.open_session()
# 获取终端
channel.get_pty()
# 激活终端,这样就可以登录到终端了,就和我们用类似于xshell登录系统一样
channel.invoke_shell()
# 下面就可以执行你所有的操作,用select实现
# 对输入终端sys.stdin和 通道进行监控,
# 当用户在终端输入命令后,将命令交给channel通道,这个时候sys.stdin就发生变化,select就可以感知
# channel的发送命令、获取结果过程其实就是一个socket的发送和接受信息的过程
while True:
  readlist, writelist, errlist = select.select([channel, sys.stdin,], [], [])
  # 如果是用户输入命令了,sys.stdin发生变化
  if sys.stdin in readlist:
    # 获取输入的内容
    input_cmd = sys.stdin.read(1)
    # 将命令发送给服务器
    channel.sendall(input_cmd)

  # 服务器返回了结果,channel通道接受到结果,发生变化 select感知到
  if channel in readlist:
    # 获取结果
    result = channel.recv(1024)
    # 断开连接后退出
    if len(result) == 0:
      print("\r\n**** EOF **** \r\n")
      break
    # 输出到屏幕
    sys.stdout.write(result.decode())
    sys.stdout.flush()

# 关闭通道
channel.close()
# 关闭链接
trans.close()

注意:在windows中,sys.stdin不是一个socket或者file-like对象,而是一个PseudoOutputFile对象,不能被select处理。所以上面的脚本不能在windows中运行,只能用于linux。

七、上例支持tab自动补全

import paramiko
import os
import select
import sys
import tty
import termios

'''
实现一个xshell登录系统的效果,登录到系统就不断输入命令同时返回结果
支持自动补全,直接调用服务器终端

'''
# 建立一个socket
trans = paramiko.Transport(('192.168.2.129', 22))
# 启动一个客户端
trans.start_client()

# 如果使用rsa密钥登录的话
'''
default_key_file = os.path.join(os.environ['HOME'], '.ssh', 'id_rsa')
prikey = paramiko.RSAKey.from_private_key_file(default_key_file)
trans.auth_publickey(username='super', key=prikey)
'''
# 如果使用用户名和密码登录
trans.auth_password(username='super', password='super')
# 打开一个通道
channel = trans.open_session()
# 获取终端
channel.get_pty()
# 激活终端,这样就可以登录到终端了,就和我们用类似于xshell登录系统一样
channel.invoke_shell()

# 获取原操作终端属性
oldtty = termios.tcgetattr(sys.stdin)
try:
  # 将现在的操作终端属性设置为服务器上的原生终端属性,可以支持tab了
  tty.setraw(sys.stdin)
  channel.settimeout(0)

  while True:
    readlist, writelist, errlist = select.select([channel, sys.stdin,], [], [])
    # 如果是用户输入命令了,sys.stdin发生变化
    if sys.stdin in readlist:
      # 获取输入的内容,输入一个字符发送1个字符
      input_cmd = sys.stdin.read(1)
      # 将命令发送给服务器
      channel.sendall(input_cmd)

    # 服务器返回了结果,channel通道接受到结果,发生变化 select感知到
    if channel in readlist:
      # 获取结果
      result = channel.recv(1024)
      # 断开连接后退出
      if len(result) == 0:
        print("\r\n**** EOF **** \r\n")
        break
      # 输出到屏幕
      sys.stdout.write(result.decode())
      sys.stdout.flush()
finally:
  # 执行完后将现在的终端属性恢复为原操作终端属性
  termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty)

# 关闭通道
channel.close()
# 关闭链接
trans.close()

八、 SSH服务端的实现

实现SSH服务端必须继承ServerInterface,并实现里面相应的方法。具体代码如下:

import socket
import sys
import threading
import paramiko

host_key = paramiko.RSAKey(filename='private_key.key')

class Server(paramiko.ServerInterface):
  def __init__(self):
  #执行start_server()方法首先会触发Event,如果返回成功,is_active返回True
    self.event = threading.Event()

  #当is_active返回True,进入到认证阶段
  def check_auth_password(self, username, password):
    if (username == 'root') and (password == '123456'):
      return paramiko.AUTH_SUCCESSFUL
    return paramiko.AUTH_FAILED

  #当认证成功,client会请求打开一个Channel
  def check_channel_request(self, kind, chanid):
    if kind == 'session':
      return paramiko.OPEN_SUCCEEDED
#命令行接收ip与port
server = sys.argv[1]
ssh_port = int(sys.argv[2])

#建立socket
try:
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  #TCP socket
  sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  sock.bind((server, ssh_port))  
  sock.listen(100)  
  print '[+] Listening for connection ...'
  client, addr = sock.accept()
except Exception, e:
  print '[-] Listen failed: ' + str(e)
  sys.exit(1)
print '[+] Got a connection!'

try:
  #用sock.accept()返回的socket实例化Transport
  bhSession = paramiko.Transport(client)
  #添加一个RSA密钥加密会话
  bhSession.add_server_key(host_key)
  server = Server()
  try:
  #启动SSH服务端
    bhSession.start_server(server=server)
  except paramiko.SSHException, x:
    print '[-] SSH negotiation failed'
  chan = bhSession.accept(20) 
  print '[+] Authenticated!'
  print chan.recv(1024)
  chan.send("Welcome to my ssh")
  while True:
    try:
      command = raw_input("Enter command:").strip("\n") 
      if command != 'exit':
        chan.send(command)
        print chan.recv(1024) + '\n'
      else:
        chan.send('exit')
        print 'exiting'
        bhSession.close()
        raise Exception('exit')
    except KeyboardInterrupt:
      bhSession.close()
except Exception, e:
  print '[-] Caught exception: ' + str(e)
  try:
    bhSession.close()
  except:
    pass
  sys.exit(1)

到此这篇关于python使用paramiko实现ssh的功能详解的文章就介绍到这了,更多相关python paramiko实现ssh内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
python基础教程之基本数据类型和变量声明介绍
Aug 29 Python
python连接mysql实例分享
Oct 09 Python
PyQt5每天必学之拖放事件
Aug 27 Python
Python之csv文件从MySQL数据库导入导出的方法
Jun 21 Python
python3+opencv3识别图片中的物体并截取的方法
Dec 05 Python
浅谈Pandas:Series和DataFrame间的算术元素
Dec 22 Python
Python爬虫 scrapy框架爬取某招聘网存入mongodb解析
Jul 31 Python
如何在windows下安装Pycham2020软件(方法步骤详解)
May 03 Python
keras中epoch,batch,loss,val_loss用法说明
Jul 02 Python
Python正则re模块使用步骤及原理解析
Aug 18 Python
python爬取微博评论的实例讲解
Jan 15 Python
Python 中 Shutil 模块详情
Nov 11 Python
python GUI库图形界面开发之PyQt5滚动条控件QScrollBar详细使用方法与实例
Mar 06 #Python
Python object类中的特殊方法代码讲解
Mar 06 #Python
python+Selenium自动化测试——输入,点击操作
Mar 06 #Python
使用 Python ssh 远程登陆服务器的最佳方案
Mar 06 #Python
使用python执行shell脚本 并动态传参 及subprocess的使用详解
Mar 06 #Python
python解析xml文件方式(解析、更新、写入)
Mar 05 #Python
如何使用pandas读取txt文件中指定的列(有无标题)
Mar 05 #Python
You might like
php实现TCP端口检测的方法
2015/04/01 PHP
PDO::errorInfo讲解
2019/01/28 PHP
Laravel 类和接口注入相关的代码
2019/10/15 PHP
laravel 框架结合关联查询 when()用法分析
2019/11/22 PHP
关于JS管理作用域的问题
2013/04/10 Javascript
JavaScript 实现简单的倒计时弹窗DEMO附图
2014/03/05 Javascript
网页实时显示服务器时间和javscript自运行时钟
2014/06/09 Javascript
DOM节点删除函数removeChild()用法实例
2015/01/12 Javascript
IE7浏览器窗口大小改变事件执行多次bug及IE6/IE7/IE8下resize问题
2015/08/21 Javascript
JS实现左右拖动改变内容显示区域大小的方法
2015/10/13 Javascript
IScroll5 中文API参数说明和调用方法
2016/05/21 Javascript
Angularjs实现带查找筛选功能的select下拉框示例代码
2016/10/04 Javascript
微信小程序中的swiper组件详解
2017/04/14 Javascript
利用Angular2的Observables实现交互控制的方法
2018/12/27 Javascript
uniapp实现可滑动选项卡
2020/10/21 Javascript
typescript编写微信小程序创建项目的方法
2021/01/29 Javascript
[08:02]DOTA2牵红线 zhou神抱得美人归
2014/03/22 DOTA
[02:46]解说DC:感谢430陪伴我们的DOTA2国际邀请赛岁月
2016/06/29 DOTA
零基础写python爬虫之使用Scrapy框架编写爬虫
2014/11/07 Python
Python实现的Excel文件读写类
2015/07/30 Python
Python方法的延迟加载的示例代码
2017/12/18 Python
Python面向对象程序设计OOP入门教程【类,实例,继承,重载等】
2019/01/05 Python
Python中函数的返回值示例浅析
2019/08/28 Python
Python numpy多维数组实现原理详解
2020/03/10 Python
Django分组聚合查询实例分享
2020/04/29 Python
Python实现迪杰斯特拉算法并生成最短路径的示例代码
2020/12/01 Python
银行会计业务的个人自我评价
2013/11/02 职场文书
资产评估专业学生的自我鉴定
2013/11/14 职场文书
成人继续教育实施方案
2014/03/01 职场文书
母婴店促销方案
2014/03/05 职场文书
酒店辞职信怎么写
2015/02/27 职场文书
环保守法证明
2015/06/24 职场文书
如何才能写好调研报告?
2019/07/03 职场文书
准备去美国留学,那么大学申请文书应该怎么写?
2019/08/12 职场文书
致创业您:正能量激励人心句子(48条)
2019/08/15 职场文书
2021年pycharm的最新安装教程及基本使用图文详解
2021/04/03 Python