# yum install gcc python-crypto python-paramiko python-devel -y
二、paramiko的连接 使用paramiko模块有两种连接方式,一种是通过paramiko.SSHClient()函数,另外一种是通过paramiko.Transport()函数。
方法一:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import paramiko ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect("某IP地址",22,"用户名", "口令")
上面的第二行代码的作用是允许连接不在know_hosts文件中的主机。
方法二:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import paramiko t = paramiko.Transport(("主机","端口")) t.connect(username = "用户名", password = "口令") 如果连接远程主机需要提供密钥,上面第二行代码可改成: t.connect(username = "用户名", password = "口令", hostkey="密钥")
三、paramiko ssh连接 以下是一个简单的通过paramiko模块定义的ssh连接并执行命令的函数,如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#!/usr/bin/python #-*- coding: utf-8 -*- import paramiko #paramiko.util.log_to_file('/tmp/sshout') def ssh2(ip,username,passwd,cmd): try: ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect(ip,22,username,passwd,timeout=5) stdin,stdout,stderr = ssh.exec_command(cmd) # stdin.write("Y") #简单交互,输入 ‘Y’ print stdout.read() # for x in stdout.readlines(): # print x.strip("\n") print '%s\tOK\n'%(ip) ssh.close() except: print '%s\tError\n'%(ip) ssh2("192.168.0.102","root","361way","hostname;ifconfig") ssh2("192.168.0.107","root","123456","ifconfig")
其中第四行的日志部分,是记录ssh连接交互时的一些信息,可以看做是类似于debug的输出,一般情况下不需要开启。
stdin.write部分是用于交互情况下,通过该命令可以执行交互。
注意这里可能会引起歧义,这里的交互并不是ssh连接过程中出现的让输入yes的交互,因为paramiko模块在连接过程中会自动处理好yes确认。
这里的交互是指后面的cmd需要的执行的程序可能出现交互的情况下,可以通过该参数进行交互。
stdout标准输出,在输出内容比较少时,可以通过直接使用read读取出所有的输出;
但在输出内容比较多时,建议通过按行读取进行处理。
不过按行读取时,每行结尾会有换行符\n,这样输出的结果很不美观。
可以通过strip进行字符串的处理。
在函数调用过程中需要注意的是,IP、username、passwd都是属于字符串型的,所以需要加引号。
后面执行的cmd,如果有多个命令需要操作时,需要通过分号进行分割。
四、paramiko sftp示例 单个文件小传下载的示例:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import paramiko #建立一个加密的管道 scp=paramiko.Transport(('192.168.0.102',22)) #建立连接 scp.connect(username='root',password='361way') #建立一个sftp客户端对象,通过ssh transport操作远程文件 sftp=paramiko.SFTPClient.from_transport(scp) #Copy a remote file (remotepath) from the SFTP server to the local host sftp.get('/root/testfile','/tmp/361way') #Copy a local file (localpath) to the SFTP server as remotepath sftp.put('/root/crash-6.1.6.tar.gz','/tmp/crash-6.1.6.tar.gz') scp.close()
一个目录下多个文件上传下载的示例:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#!/usr/bin/env python #-*- coding: utf-8 -*- import paramiko,datetime,os hostname='192.168.0.102' username='root' password='361way' port=22 local_dir='/tmp/getfile' remote_dir='/tmp/abc' try: t=paramiko.Transport((hostname,port)) t.connect(username=username,password=password) sftp=paramiko.SFTPClient.from_transport(t) #files=sftp.listdir(dir_path) files=sftp.listdir(remote_dir) for f in files: print '' print '#########################################' print 'Beginning to download file from %s %s ' % (hostname,datetime.datetime.now()) print 'Downloading file:',os.path.join(remote_dir,f) sftp.get(os.path.join(remote_dir,f),os.path.join(local_dir,f))#下载 #sftp.put(os.path.join(local_dir,f),os.path.join(remote_dir,f))#上传 print 'Download file success %s ' % datetime.datetime.now() print '' print '##########################################' t.close() except Exception: print "connect error!"
注:本处的目录下所有文件进行下载或上传的示例中,在遇到目录下还有嵌套的目录存在时,会将目录也当做文件进行处理,所以如果想要更加的完美的话,可以通过引入stat模块下的S_ISDIR方法进行处理
paramiko.transport对象也支持以socket的方式进行连接,如下示例:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import paramiko transport = paramiko.Transport(('localhost',22)) transport.connect(username='root', password = 'password') sftp = paramiko.SFTPClient.from_transport(transport) sftp.get(remotefile,localfile) #如果是上传则用: #sftp.put(localfile, remotefile) transport.close() #用socket连接 tcpsock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) tcpsock.settimeout(5) tcpsock.connect((ip,22),) ssh = paramiko.Transport(tcpsock) ssh.connect(username=user,password=password) sftpConnect=paramiko.SFTPClient.from_transport(ssh)
五、利用paramiko实现ssh的交互式连接 以下是通过paramiko模块直接用ssh协议登陆到远程服务器的操作代码,这里先定义一个interactive模块,代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import socket import sys # windows does not have termios... try: import termios import tty has_termios = True except ImportError: has_termios = False def interactive_shell(chan): if has_termios: posix_shell(chan) else: windows_shell(chan) def posix_shell(chan): import select oldtty = termios.tcgetattr(sys.stdin) try: tty.setraw(sys.stdin.fileno()) tty.setcbreak(sys.stdin.fileno()) chan.settimeout(0.0) while True: r, w, e = select.select([chan, sys.stdin], [], []) if chan in r: try: x = chan.recv(1024) if len(x) == 0: print '\r\n*** EOF\r\n', break sys.stdout.write(x) sys.stdout.flush() except socket.timeout: pass if sys.stdin in r: x = sys.stdin.read(1) if len(x) == 0: break chan.send(x) finally: termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty) # thanks to Mike Looijmans for this code def windows_shell(chan): import threading sys.stdout.write("Line-buffered terminal emulation. Press F6 or ^Z to send EOF.\r\n\r\n") def writeall(sock): while True: data = sock.recv(256) if not data: sys.stdout.write('\r\n*** EOF ***\r\n\r\n') sys.stdout.flush() break sys.stdout.write(data) sys.stdout.flush() writer = threading.Thread(target=writeall, args=(chan,)) writer.start() try: while True: d = sys.stdin.read(1) if not d: break chan.send(d) except EOFError: # user hit ^Z or F6 pass
代码内容可以从paramiko 在github项目上的demo里获取。再另外写一个ssh_inter.py的交互主程序,内容如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import paramiko import interactive #记录日志 paramiko.util.log_to_file('/tmp/test') #建立ssh连接 ssh=paramiko.SSHClient() ssh.load_system_host_keys() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect('192.168.0.102',port=22,username='root',password='xxxxxx',compress=True) #建立交互式shell连接 channel=ssh.invoke_shell() #建立交互式管道 interactive.interactive_shell(channel) #关闭连接 channel.close() ssh.close() 执行效果就像我们平时直接使用ssh登录一样。
六、总结 paramiko模块是一个比较强大的ssh连接模块,以上的示例只是列出了该模块的一些简单的使用方法,还可以使用threading模块加块程序并发的速度;
也可以使用configparser模块处理配置文件,而我们将所有IP、用户信息操作都放入配置文件;使用setproctitle模块为执行的程序加一个容易区分的title等。
同样,虽然连fabric这样大名鼎鼎的软件使用的ssh都是用paramiko模块进行的封装,不过你依然可以选择不使用它,
你也可以选择pexpect模块实现封装一个简易的ssh连接工具、或者使用同样比较火的salt-ssh模块。
服务端是一个守护进程(daemon),他在后台运行并响应来自客户端的连接请求。服务端一般是sshd进程,提供了对远程连接的处理,一般包括公共密钥认证、密钥交换、对称密钥加密和非安全连接。
客户端包含ssh程序以及像scp(远程拷贝)、slogin(远程登陆)、sftp(安全文件传输)等其他的应用程序。
他们的工作机制大致是本地的客户端发送一个连接请求到远程的服务端,服务端检查申请的包和IP地址再发送密钥给SSH的客户端,本地再将密钥发回给服务端,自此连接建立。SSH 1.x和SSH 2.x在连接协议上有一些差异。
一旦建立一个安全传输层连接,客户机就发送一个服务请求。当用户认证完成之后,会发送第二个服务请求。这样就允许新定义的协议可以与上述协议共存。连接协议提供了用途广泛的各种通道,有标准的方法用于建立安全交互式会话外壳和转发(“隧道技术”)专有 TCP/IP 端口和 X11 连接。
SSH被设计成为工作于自己的基础之上而不利用超级服务器(inetd),虽然可以通过inetd上的tcpd来运行SSH进程,但是这完全没有必要。启动SSH服务器后,sshd运行起来并在默认的22端口进行监听(你可以用 # ps -waux | grep sshd 来查看sshd是否已经被正确的运行了)如果不是通过inetd启动的SSH,那么SSH就将一直等待连接请求。当请求到来的时候SSH守护进程会产生一个子进程,该子进程进行这次的连接处理。