首页 > 编程语言 > 详细

python paramiko登陆设备

时间:2020-02-28 10:51:23      阅读:145      评论:0      收藏:0      [点我收藏+]

一,单线程 - shell交互

def chan_recv(chan):
    data = chan.recv(1024)            # 收1024数据
    sys.stdout.write(data.decode())   # 输出
    sys.stdout.flush()

if __name__ == ‘__main__‘:
    ssh = paramiko.SSHClient()
    ssh.load_system_host_keys()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect(‘10.10.10.2‘, port=22, username=‘cisco‘, password=‘cisco‘, timeout=3)  # 3秒超时
    channel = ssh.invoke_shell()

    chan_recv(channel)       # 开始前先收一下数据
    while True:              # 监听输入
        d = input()
        if d == ‘quit‘:      # 如果输入quit,就退出
            break
        channel.send(d + ‘\n‘)
        chan_recv(channel)

    channel.close()
    ssh.close()

问题:接收数据时的不规则性,chan.recv(1024)每次只收1024数据:

1,如果发送方的数据大于1024,就导致一次就取不完,需要分多次取

2,粘包问题: 即使发送方数据小于1024,但是如果去缓存取数据的时候数据还没到达,也会导致一次取不完;而且也可能会取到下一次命令的返回数据,即如果交互多次,此时输入命令和拿到的结果无法一一对应,

以上代码在执行时,获取不到预期结果时,多敲几个回车就会出结果

 

解决方法:

1,第二个粘包问题可以通过sleep粗暴解决

2,如果想把两个问题同时解决,主要有三个方法:

  a)发送实际数据前,server端先发数据大小,client端持续接收,并且最后一次不收1024,而收实际大小,但是像paramiko这种server端无法改造的不适用(老男孩python socket编程就是这种解决思路)

  b)明确结尾标示符,即做回显判断,每输入一条命令,都接收到“结尾标示符”为止,参考“python paramiko自动登录网络设备抓取配置信息”

  c)多线程,主线程做输入,子线程持续不断接收


二,多线程 - shell交互

def chan_recv(chan):
    while True:
        data = chan.recv(1024)      # data是收到的数据,每次收1024
        if not data:    # 客户端输入了断开socket的命令(例如exit),会导致子线程循环结束
            break
        sys.stdout.write(data.decode())
        sys.stdout.flush()


if __name__ == ‘__main__‘:
    ssh = paramiko.SSHClient()
    ssh.load_system_host_keys()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect(‘10.10.10.2‘, port=22, username=‘cisco‘, password=‘cisco‘, timeout=3)  # 3秒超时
    channel = ssh.invoke_shell()

# 这里如果不设置daemon进程,即使主线程关闭退出,子线程也不会结束 writer = threading.Thread(target=chan_recv, args=(channel,), daemon=True) writer.start() while True: d = input() if d == ‘quit‘: break channel.send(d + ‘\n‘) # writer.join() # 这里不用join了,线程已经设置为守护线程,主线程结束就会自动关闭守护线程了
channel.close() ssh.close()

备注:

1,可以看到相比单线程-shell交互,多线程版的子线程可以通过while循环接收server,也就不用去关心粘包、一次收1024能不能收完这类问题了

2,server端可能会有交互要求输入,例如server端可能进行了分屏,返回--More--,要求输入空格后,才继续显示,此时需要先取消分屏

3,输入一条命令,界面上会显示两遍,第一遍是自己客户端输入的,第二遍是server端的回显

 

三,多线程 - 执行预先定义的命令

本例是对“python paramiko自动登录网络设备抓取配置信息”的改进,无需事先确定回显内容

def chan_recv(chan):
    global resp                  # 让主线程获取子线程的结果,使用全局变量
    while True:
        data = chan.recv(1024)  
        if not data:
            break
        resp += data.decode()

if __name__ == ‘__main__‘:
    ssh = paramiko.SSHClient()
    ssh.load_system_host_keys()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect(‘10.10.10.2‘, port=22, username=‘cisco‘, password=‘cisco‘, timeout=3)  # 3秒超时
    channel = ssh.invoke_shell()

    cmds = [‘enable\n‘, ‘cisco123\n‘, ‘terminal length 0\n‘, ‘show run\n‘, ‘exit\n‘]

    resp = ‘‘
    writer = threading.Thread(target=chan_recv, args=(channel,))
    writer.start()
    for cmd in cmds:
        channel.send(cmd)

    # 这里一定要join(),让主线程等待子线程执行结束,否则主线程不等子线程收完数据直接往下执行了
    writer.join()   
    print(resp)

    channel.close()
    ssh.close()

总结:

结尾的判断主要有三种方法:参考https://www.cnblogs.com/litaozijin/p/6624029.html

1,服务器端预先发送数据长度,每次接收时判断(老男孩python课件中socket编程也是这个方法)

2,结尾标示符

3,终止socket

 

收数据时,也有:

1,单线程

2,多线程:主线程发送命令,子线程负责持续接收

 

案例三,采用了多线程 + 终止socket的方法

 

python paramiko登陆设备

原文:https://www.cnblogs.com/guxh/p/12375801.html

(1)
(1)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!