ToB企服应用市场:ToB评测及商务社交产业平台

标题: Flask 运用Xterm实现交互终端 [打印本页]

作者: 曹旭辉    时间: 2024-1-14 19:45
标题: Flask 运用Xterm实现交互终端
Xterm是一个基于X Window System的终端仿真器(Terminal Emulator)。Xterm最初由MIT开发,它允许用户在X Window环境下运行文本终端程序。Xterm提供了一个图形界面终端,使用户能够在图形桌面环境中运行命令行程序。而xterm.js是一个用于在浏览器中实现终端仿真的JavaScript库。它允许在Web页面中创建交互式的终端界面,用户可以在浏览器中运行命令行程序,执行命令,并与终端进行交互。
主要特点和功能包括:
xterm.js通常被用于Web应用程序中,尤其是在需要提供命令行界面的场景下,如在线终端、远程服务器管理等。这使得开发者能够在浏览器中实现类似于本地终端的交互体验,而无需使用本地终端模拟器。
AJAX 实现Web交互

AJAX(Asynchronous JavaScript and XML)是一种用于在Web应用程序中实现异步数据交换的技术。它允许在不重新加载整个页面的情况下,通过在后台与服务器进行小规模的数据交换,实现动态更新网页内容的目的。AJAX广泛用于创建交互性强、用户体验良好的Web应用程序,例如在加载新数据、进行表单验证、实现自动完成搜索等方面。
如下前端部分,通过使用ajax向后端提交数据,当success:function接收到数据后直接将数据动态回写到Xterm终端上,代码如下所示;
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <title>Title</title>
  6.     <link rel="stylesheet" href="https://www.lyshark.com/javascript/xterm/xterm.css" />
  7.    
  8.    
  9. </head>
  10. <body>
  11.    
  12.    
  13.    
  14.         <input type="text" id="address" placeholder="主机地址"/>
  15.         <input type="text" id="command" placeholder="执行命令"/>
  16.         <input type="button" value="执行命令" onclick="show()">
  17.    
  18. </body>
  19. </html>
复制代码
后端部分的实现很简单,首先封装一个ssh_shell用于执行命令,用户传入数据后,直接执行并将返回结果放入到ref内即可。
  1. from flask import Flask,render_template,request
  2. from flask import jsonify
  3. import paramiko
  4. app = Flask(__name__)
  5. ssh = paramiko.SSHClient()
  6. ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
  7. def ssh_shell(address,username,password,port,command):
  8.     ssh.connect(address,port=port,username=username,password=password)
  9.     stdin, stdout, stderr = ssh.exec_command(command)
  10.     result = stdout.read()
  11.     if not result:
  12.         result=stderr.read()
  13.     ssh.close()
  14.     return result.decode()
  15. @app.route('/', methods=[ 'GET', 'POST'])
  16. def index():
  17.     if request.method == "POST":
  18.         # 接收数据
  19.         json_value = request.get_json()
  20.         ref = ssh_shell("192.168.150.128","root","123123","22",json_value["command"])
  21.         # 发送数据
  22.         info = dict()
  23.         info["address"] = json_value["address"]
  24.         info["command"] = ref
  25.         return jsonify(info)
  26.     else:
  27.         return render_template("index.html")
  28. if __name__ == '__main__':
  29.     app.run()
复制代码
AJAX实现Web终端

继续扩展将编辑框去掉,用户输入数据后直接传入到Xterm内,Xterm里卖弄判断如果出现了回车,则像后端发送ajax数据,否则继续侦听并记下输入数据。
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <title>Title</title>
  6.     <link rel="stylesheet" href="https://www.lyshark.com/javascript/xterm/xterm.css" />
  7.    
  8.    
  9. </head>
  10. <body>
  11.    
  12.    
  13. </body>
  14. </html>
复制代码
后端收到数据后解析命令,比对命令是否存在,根据不同的命令执行不同的分支。
  1. from flask import Flask,render_template,request
  2. from flask import jsonify
  3. app = Flask(__name__)
  4. @app.route('/', methods=[ 'GET', 'POST'])
  5. def index():
  6.     if request.method == "POST":
  7.         # 接收数据
  8.         json_value = request.get_json()["command"]
  9.         if len(json_value) != 0:
  10.             # 判断使用哪一个分支
  11.             splite_value = json_value.split(" ")
  12.             info = dict()
  13.             if splite_value[0] == "help":
  14.                 info["value"] = "version 1.0"
  15.                 info["value"] = info["value"] + "\n[shell] # "
  16.                 return jsonify(info)
  17.             elif splite_value[0] == "GetCPU":
  18.                 address = splite_value[1]
  19.                 info["value"] = "192.168.1 CPU 10%"
  20.                 info["value"] = info["value"] + "\n[shell] # "
  21.                 return jsonify(info)
  22.             else:
  23.                 info["value"] = "命令不存在"
  24.                 info["value"] = info["value"] + "\n[shell] # "
  25.                 return jsonify(info)
  26.         else:
  27.             info = dict()
  28.             info["value"] = "[shell] # "
  29.             return jsonify(info)
  30.     else:
  31.         return render_template("index.html")
  32. if __name__ == '__main__':
  33.     app.run()
复制代码
运行后可输出一个交互式WebShell环境,如下图所示;

WebSocket 实现终端

虽然WebSSH可以方便管理主机,但如果需要批量运维则需要开发一个可以多条消息共同推送的命令行。
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <title>Title</title>
  6.     <link rel="stylesheet" href="https://www.lyshark.com/javascript/xterm/xterm.css" />
  7.    
  8.    
  9. </head>
  10. <body>
  11.    
  12.    
  13. </body>
  14. </html>   
复制代码
后台接收参数,并更具不同的参数执行不同的运维函数,此处只做演示,具体功能需要自行编写。
  1. from flask import Flask,render_template,request
  2. from flask_socketio import SocketIO
  3. async_mode = None
  4. app = Flask(__name__)
  5. app.config['SECRET_KEY'] = "lyshark"
  6. socketio = SocketIO(app)
  7. @app.route("/")
  8. def index():
  9.     return render_template("index.html")
  10. # 出现消息后,率先执行此处
  11. @socketio.on("message",namespace="/Socket")
  12. def socket(message):
  13.     print("接收到消息:",message['command'])
  14.     command = message['command']
  15.     if len(command) != 0:
  16.         splite_command = command.split(" ")
  17.         if splite_command[0] == "help":
  18.             socketio.emit("response", {"value": "version 1.0 \n"}, namespace="/Socket")
  19.         elif splite_command[0] == "Ping":
  20.             if len(splite_command) == 2:
  21.                 index = splite_command[1]
  22.                 for each in range(int(index)):
  23.                     socketio.sleep(0.1)
  24.                     socketio.emit("response",{"value": str(each) + "\n"}, namespace="/Socket")
  25.                 socketio.emit("response", {"value": "\n[shell] # "}, namespace="/Socket")
  26.         else:
  27.             socketio.emit("response", {"value": "lyShell: command not found \n"}, namespace="/Socket")
  28.     else:
  29.         socketio.emit("response", {"value": "[shell] # "}, namespace="/Socket")
  30. # 当websocket连接成功时,自动触发connect默认方法
  31. @socketio.on("connect",namespace="/Socket")
  32. def connect():
  33.     print("链接建立成功..")
  34. # 当websocket连接失败时,自动触发disconnect默认方法
  35. @socketio.on("disconnect",namespace="/Socket")
  36. def disconnect():
  37.     print("链接建立失败..")
  38. if __name__ == '__main__':
  39.     socketio.run(app,debug=True)
复制代码
Socket版本的将会更流畅,如下图所示;


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4