Bootstrap

【简洁明了】xterm.js+paramiko+websocket实现Web终端,可ssh连接linux bash

项目要求,需要在web使用ssh或者控制台,就找有没有好的方法可以实现,找到了xterm.js+paramiko+websocket等实现交互,xtarm.js可以在前端展示一个终端,可以自定义,通过websocket和后端进行通信,后端可以自己写一个脚本程序,配置一个websocket的server端进行通信。
paramiko

python执行终端命令

在这里我本来想的是直接在python里调用终端命令执行,但是单独使用的时候可以,集成起来就不好用了,为什么不好用后面说,先说几种常用的终端命令的执行。

os.system

import os
os.system('ls')

会启动一个子进程调用command执行命令,在终端直接执行会显示结果,在程序中使用只会有返回值,结果不会返回。

os.popen

os.popen(command,mode)

import os
os.popen('cat /proc/cpuinfo')

直接与command进程通信的一个管道,返回一个文件对象,mode可以指定模式,如果是’r’,可以使用read()或者readlines()方法读取返回的执行结果。

commands

import commands
status=commands.getstatus('cat /proc/cpuinfo')
output=commands.getoutput('ls -l')
(status,output)=commands.getstatusoutput('ls -l')

会返回一个元组,包含执行结果和返回的状态。output中包含了控制台的输出信息和错误信息等。

subprocess

是python2.4出现的一个模块,可以代替上面的模块方法,还集中了多个关于进程的操作。call()完全替代了system()popen()Popen类进行实现和完善。

websocket

这个没什么好介绍的(就是我不想写,直接百度都是,而且主要是看实现的过程,概念这些东西估计也没多少人想看)。
主要就是,它是socket的更高级版本吧,然后呢,可以双方都使用websocket进行通信,会比较方便;也可以使用socket进行,如python中使用socket实现服务端,客户端使用websocket进行连接。
但是会非常麻烦,需要自己处理握手通信以及数据的编码解码等处理操作,虽然网上可以找到很多,但是我看了好些综合了好几个博客的代码,都没有实现,接收到的数据都是乱码,而且我传输的都是英文,没有中文,也不涉及编码混乱的问题,因此呢,手动实现就可以放弃了。
然后我找到由第三方库实现websocket的功能。

websockets

这是github
但是好像需要python3版本才行,我是2,就放弃了。

simple-websocket-server

这是github
这个我试了一下很好用,主要是很方便,把websocket的操作都封装好了,直接使用就行了,
官方示例如下,看代码也不用多解释,建立一个连接,然后新建一个类,有三个方法处理三个事件就好了。

from SimpleWebSocketServer import SimpleWebSocketServer, WebSocket

class SimpleEcho(WebSocket):

    def handleMessage(self):
        # echo message back to client
        self.sendMessage(self.data)

    def handleConnected(self):
        print(self.address, 'connected')

    def handleClose(self):
        print(self.address, 'closed')

server = SimpleWebSocketServer('', 8000, SimpleEcho)
server.serveforever()

问题来了,就是在这里,单独用脚本执行commands.getstatusoutput没有问题,但是放在这个框架里就有问题来了,所以在这里没法用。
然后呢,这个框架有点问题,如果你的程序在运行中突然断开连接了,或者刚连上就断开了,说明代码有问题,这个库代码出错是不会报错的,只会断开连接。善用print调试,定位出错位置。

paramiko

ssh是一个协议,OpenSSH是其中一个开源实现,paramiko是Python的一个库,实现了SSHv2协议(底层使用cryptography)。

有了Paramiko以后,我们就可以在Python代码中直接使用SSH协议对远程服务器执行操作,而不是通过ssh命令对远程服务器进行操作。
安装的话,直接pip就行了

pip install paramiko

这里只介绍SSHClient
基本使用如下

def sshConnection():
	ip    = '192.168.1.104'
	port  = 22
	user  = 'root'
	passwd= 'root'

	cmd = 'cd /home/kang/Desktop'
	# 设置记录日志
	log_file = 'kali_ssh.log'
	util.log_to_file(log_file)

	# 生成ssh客户端实例
	s = SSHClient()
	s.set_missing_host_key_policy(AutoAddPolicy())
	print ("[+] Start ssh into: "+ip)
	s.connect(ip, port, user, passwd)
	print ("[+] SSH established !")
	s.exec_command('ls -l')
	recv=s.recv(1024)
	print(recv)
	chan.close()
	s.close()

非交互式:ssh_client.exec_command

但是有一个小问题,这里如果使用exec_command,他是非交互式的,差不多就是每次只能执行一条,如果需要使用环境变量啥的,就不行了,得bash -ls 'ls -l’才行。如果需要执行多条语句,使用;分隔开。
而且如果出现比如进入python终端这种情况,exec_command就无法执行了,会卡住,可能是无法判断出后台终端的响应。

交互式:channel.invoke_shell

比较推荐的是交互式的方式,相当于创建一个shell终端,在其中运行命令,但是这个的问题是,如何判断命令是否执行完成,如果等的时间太短可能获取不到结果,如果等的时间太长用户体验不好。
这里通过返回的SP1输入提示符进行判断,在返回结果的最后都会返回一个输入的提示符,而每个界面或者系统的提示符不同,可能会有# 结尾的,也可能是$ 结尾的。因此可以把这些添加到一个list中,进行判断。
下面是一个示例

import paramiko
import time
 
hostname = '192.16.21.12'
port = 22
username = 'hadoop'
password = 'hadoop'
timeout = 10
 
 
def runCommand
;