python连接远程服务器上传文件、执行Command并取回结果

功能:

  1. 连接远程服务器
  2. 上传本地文件到服务器中,下载服务器中文件到本地
  3. 运行服务器中的程序/执行command

使用paramiko库完成上述功能。paramiko提供了SSHv2协议的一个抽象,可以完成客户端和服务器端的功能。在我要完成的功能中,主要是客户端的程序。

函数的逻辑:

开ssh连接–>上传文件–>执行服务器中程序–>取文件

开ssh连接

一个错误示范下面:

import paramiko
ssh_client=paramiko.SSHClient()
ssh_client.connect(hostname=’hostname’,username=’mokgadi’,password=’mypassword’)

如果思路非常直接的实例化一个paramiko.SSHClient()对象,然后就进行连接,会出现一个error:

missing_host_key raise SSHException(‘Server %r not found in known_hosts’ % hostname) paramiko.ssh_exception.SSHException: Server ‘hostname’ not found in known_hosts

这是由于没有告诉本机可以“信任”待访问的远程服务器。如果以命令行执行的话,会有如下信息:

The authenticity of host ‘hostname’ can’t be established.RSA key fingerprint is ‘key’. Are you sure you want to continue connecting (yes/no)?

这涉及到网络安全中公私钥的问题,比较复杂网络安全课没好好上 不做讨论。总之需要告诉本机,要访问的服务器是可以信任的,Paramiko提供了这样的机制,那么开启ssh连接的正确示范:

ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_client.connect(hostname = hostname, port = port, username = username, password=password)

需要提前定义好 hostname,port,username,password。

上传文件

上传文件使用sftp协议,sftp是一个基于ssh的协议,所以要在ssh连接后开启sftp连接。可以使用paramiko提供的open_sftp()函数,我也看到了很多使用transform对象的方法,但是个人认为基于ssh后开启sftp最直观。
逻辑就是开启连接–>上传–>关闭连接。

ftp_client_up = ssh_client.open_sftp()
ftp_client_up.put(local_file,remote_file)
ftp_client_up.close()

其中需要提前定义好local_fileremote_file。需要注意的是,必须写明文件名且两种必须一样,如下所示:

local_file = '/Users/xxx/xxx/1.txt'
remote_file = '/home/username/xxx/1.txt'

执行服务器中程序/执行command

执行服务器中的程序是通过命令行完成的,cd到对应目录 python xxx完成的,所以先介绍执行command的方式。通过库中exec_command函数完成

stdin,stdout,stderr=ssh_client.exec_command("ls")

需要注意的是,exec_command每次通过开一个新的Channel来执行传输的命令,并通过stdin、stdout和stderr的这些类似于Python文件对象的返回,理论上只能执行一条命令。也就是第一行exec_command("cd xxx")第二行执行xxx文件中的某个程序python xxx.py这种方式是不行的,此时会回到根目录。我大概是利用了一种漏洞,在exec_command中一次执行多个,那就是把要执行的命令之间用\n分开,且最后一个不要有。

stdin,stdout,stderr=ssh_client.exec_command("xxx\n xxx\n xxx")

但我需要执行的程序需要开启虚拟环境且需要使用GPU。怎么做呢?

由于每次exec_command它并不像bash一样,一启动就会通过source ~/.bashrv执行所有的系统命令,此后所有运行的command都相当于这个bash的子进程,因此需要用绝对路径开启虚拟环境source /home/xxx/anaconda3/bin/activate venv

对于开启GPU,它是通过环境变量来配置运行的,还是上述的问题,所以就作为临时的变量,使用export AAA=bbb来配置。

【这部分对于bash的理解纯属个人观点,可能并不正确,欢迎讨论。】

取文件

由于我运行的程序会将结果写到文件中,所以类似put,再get回一个文件,逻辑和上传是一样的

ftp_client_down_re = ssh_client.open_sftp()
ftp_client_down_re.get(remote_path,local_path)
ftp_client_down_re.close()

也需要提前定义好local_pathremote_path。需要注意的是,必须写明文件名且两种必须一样,如下所示:

local_path = '/Users/xxx/xxx/1.txt'
remote_path = '/home/username/xxx/1.txt'

逻辑是开启连接–>下载–>关闭连接

最后在所有完成以后关闭ssh连接

ssh_client.close()

个人建议将这段代码写成一个函数进行调用。虽然不写大概率能运行成功,但是会出现它自己释放时候出问题,报错如下:

Exception ignored in: <object repr() failed>
Traceback (most recent call last):
File “/Users/xxx/xxx/lib/python3.5/site-packages/paramiko/file.py”, line 66, in del
File “/Users/xxx/xxx/lib/python3.5/site-packages/paramiko/file.py”, line 84, in close
File “/Users/xxx/xxx/lib/python3.5/site-packages/paramiko/file.py”, line 93, in flush
TypeError: ‘NoneType’ object is not callable

可能是因为sys.exit()的问题,把这个交给调用函数之后来完成应该不会出这个问题。以及如果多个command去exec,最后一个带着\n也可能会出现这个问题。

完整代码

import paramiko

def fun():
	hostname = 'xxx'
	port = xxx
	username='xxx'
	password = 'xxxx'
	#文件名务必一致
	local_file = '/Users/xxx/xxxx/1.txt'
	remote_file = '/home/xxx/xxx/1.txt'

	ssh_client = paramiko.SSHClient()
	ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
	ssh_client.connect(hostname = hostname, port = port, username = username, password=password)

	ftp_client_up = ssh_client.open_sftp()
	ftp_client_up.put(local_file,remote_file)
	ftp_client_up.close()

	stdin,stdout,stderr=ssh_client.exec_command("xxx\n xxx\n xxxx")
	# print(stderr.readlines())
	print(stdout.readlines())

	local_path = '/Users/xxx/xxx/result.txt'
	remote_path = '/home/xxx/xxx/result.txt'

	ftp_client_down_re = ssh_client.open_sftp()
	ftp_client_down_re.get(remote_path,local_path)
	ftp_client_down_re.close()

	ssh_client.close()

fun()
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值