xterm展示窗口,绑定从服务端获取到的流-》客户端和服务端建立websocket连接-》paramiko连接服务器-》获取流-》通过send发送给客户端-》客户端通过通道接收发送消息-》服务端接收消息发送到linux
npm install --save xterm xterm-addon-fit xterm-addon-attach
<template>
<div class="box">
<div id="xterm" class="xterm-box"></div>
</div>
</template>
<script>
import { Terminal } from 'xterm'
import { FitAddon } from 'xterm-addon-fit'
import 'xterm/css/xterm.css'
import 'xterm/lib/xterm.js'
export default {
data() {
return {
term: null,
socket: '',
WebSocketUrl: 'ws:localhost:5000/websocketconn',
//WebSocketUrl: 'ws:192.168.5.10:8080/terminal/17317181717', //ws接口ws:192.168.5.10:8080/terminal/17317181717
// 心跳
lockReconnect: false, //是否真正建立连接
timeout: 60 * 1000, //60秒一次心跳
timeoutObj: null, //心跳心跳倒计时
serverTimeoutObj: null, //心跳倒计时
timeoutnum: null, //断开 重连倒计时
}
},
mounted() {
this.init(this.WebSocketUrl)
},
//跑路前清除定时器
beforeDestroy() {
this.close()
clearTimeout(this.timeoutObj)
clearTimeout(this.serverTimeoutObj)
clearTimeout(this.timeoutnum)
},
methods: {
// 心跳函数--------------
reconnect() {
//重新连接
var that = this
if (that.lockReconnect) {
return
}
that.lockReconnect = true
//没连接上会一直重连,设置延迟避免请求过多
that.timeoutnum && clearTimeout(that.timeoutnum)
that.timeoutnum = setTimeout(function () {
//新连接
that.init(that.WebSocketUrl)
that.lockReconnect = false
}, 2000)
},
reset() {
//重置心跳
var that = this
//清除时间
clearTimeout(that.timeoutObj)
clearTimeout(that.serverTimeoutObj)
//重启心跳
that.start()
},
start() {
//开启心跳
var self = this
self.timeoutObj && clearTimeout(self.timeoutObj)
self.serverTimeoutObj && clearTimeout(self.serverTimeoutObj)
self.timeoutObj = setTimeout(function () {
//这里发送一个心跳,后端收到后,返回一个心跳消息,
if (self.socket.readyState == 1) {
//如果连接正常,有事没事发ping,具体根据要求
//self.socket.send('ping')
} else {
//否则重连
self.reconnect()
}
self.serverTimeoutObj = setTimeout(function () {
//超时关闭
self.close()
}, self.timeout)
}, self.timeout)
},
//-----------------
initXterm() {
if (this.term) {
this.term.dispose()
}
let height = document.body.clientHeight
this.term = new Terminal({
rendererType: 'canvas', //渲染类型
rows: 35, //行数 18是字体高度,根据需要自己修改
convertEol: true, //启用时,光标将设置为下一行的开头
scrollback: 800, //终端中的回滚量
disableStdin: false, //是否应禁用输入
cursorStyle: 'underline', //光标样式
cursorBlink: true, //光标闪烁
tabStopWidth: 8, //制表宽度
screenKeys: true,
theme: {
foreground: 'yellow', //字体
background: '#060101', //背景色
cursor: 'help', //设置光标
},
})
this.term.writeln('Welcome to use Superman. ')
this.term.open(document.getElementById('xterm'))
const fitAddon = new FitAddon()
this.term.loadAddon(fitAddon)
fitAddon.fit() //全屏
//window.addEventListener('resize', this.resizeScreen)
// 支持输入与粘贴方法
let _this = this //一定要重新定义一个this,不然this指向会出问题
let code = ''
let codeArr = '' //存储输入集合
this.term.onData(function (key) {
_this.socket.onsend(key)
//codeArr += key
//_this.term.write(key)
// let order = { operate: 'command', command: key }
//这里key值是你输入的值,数据格式order一定要找后端要!!!!
//if (key.length > 1) _this.term.write(key) //粘贴
//console.log(key, JSON.stringify(key))
// alert(key)
})
},
init(url) {
// 实例化socket
this.socket = new WebSocket(url)
// 监听socket连接
this.socket.onopen = this.open
// 监听socket错误信息
this.socket.onerror = this.error
// 监听socket消息this.getMessage
this.socket.onmessage =(mes)=>{
this.term.write(mes.data) //这里write也许不是固定的,失败后找后端看一下该怎么往term里面write
//收到服务器信息,心跳重置
this.reset()
}
// 发送socket消息
this.socket.onsend = (order)=>{
// alert(order)
this.socket.send(order)
}
},
open: function () {
alert("success")
console.log('socket连接成功')
//this.term.write('Welcome to use')
this.initXterm()
//开启心跳
this.socket.send("")
this.start()
},
error: function () {
console.log('连接错误')
//重连
this.reconnect()
},
close: function () {
alert("close")
this.socket.close()
console.log('socket已经关闭')
console.log(e.code + ' ' + e.reason + ' ' + e.wasClean)
//重连
this.reconnect()
},
getMessage: function (msg) {
alert("22")
console.log("****")
console.log(msg)
//msg是返回的数据
//msg = JSON.parse(msg.data)
//msg = msg.data
//console.log(msg)
//this.socket.send('ping') //有事没事ping一下,看看ws还活着没
//switch用于处理返回的数据,根据返回数据的格式去判断
// switch (msg['operation']) {
// case 'stdout':
// this.term.write(msg['data']) //这里write也许不是固定的,失败后找后端看一下该怎么往term里面write
// break
// default:
// console.log('Unexpected message type:', msg) //但是错误是固定的。。。。
// }
this.term.write(msg['data']) //这里write也许不是固定的,失败后找后端看一下该怎么往term里面write
//收到服务器信息,心跳重置
this.reset()
},
// send: function (order) {
// //console.log(order)
// this.socket.send(order)
// },
resizeScreen(size) {
console.log('size', size)
var fitAddon = new FitAddon()
term.loadAddon(fitAddon)
try {
fitAddon.fit()
// 窗口大小改变时触发xterm的resize方法,向后端发送行列数,格式由后端决定
term.onResize((size) => {
//_this.onSend({ Op: 'resize', Cols: size.cols, Rows: size.rows })
})
} catch (e) {
console.log('e', e.message)
}
},
},
}
</script>
</script>
<!-- <style lang="scss" scoped>
.box {
width: 100%;
height: 100%;
.xterm-box {
width: 100%;
height: 100%;
}
}
</style> -->
from flask_sockets import Sockets
# app = getapp()
manager = Manager(app)
Migrate(app, db)
sockets = Sockets(app)
import paramiko
def _ssh(host,username,password,port=22):
client = paramiko.SSHClient()
#2.解决问题:如果之前没有,连接过的ip,会出现选择yes或者no的操作,
##自动选择yes
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
#3.连接服务器
client.connect(hostname=host,
port=22,
username=username,
password=password)
channle = client.invoke_shell(term='xterm')
return channle
except:
return False
def recv_ssh_msg(channle,ws):
'''
channle: 建立好的SSH连接通道 这个函数会不停的接收ssh通道返回的命令 返回到前端的ws套接字里
'''
while not channle.exit_status_ready():
try:
buf = channle.recv(1024) # 接收命令的执行结果
print("buff:::",buf.decode())
ws.send(buf.decode()) # 向Websocket通道返回 except:
break
except:
pass
plist=[]
import threading
@sockets.route('/websocketconn')
def webssh(ws):
channle = _ssh("43.143.177.197", username="root", password="123456789Gg")
'''
1: 接收前端(ws)的命令,发给后台(ssh) 2: 接收后台的返回结果,给到前端
'''
while not ws.closed:
message = ws.receive() # 接收到消息
t = threading.Thread(target=recv_ssh_msg,args=(channle,ws))
t.setDaemon(True)
t.start() # 线程开启
channle.send(message) # 由SSH通道转交给Linux环境 else: # 连接断开 跳出循环
if __name__=="__main__":
# manager.run()
# app.run()
from gevent import pywsgi
from geventwebsocket.handler import WebSocketHandler
server = pywsgi.WSGIServer(("localhost", 5000), app, handler_class=WebSocketHandler)
print("web server start ... ")
server.serve_forever()