实现在 Web 网页上管理你的远程控制台程序

目的

诸如 cmd.exe/bash 等程序是在控制台上运行交互的,我们将把控制台的交互能力完全移动到 Web 界面上来,实现在网页上对一个进程进行管理(类似于一个终端)。

效果图

这是执行 ls -al 命令的结果在网页上显示。

实现方案

child_process 子进程 模块用于启动 bash/cmd.exe,并监听输入输出流。

使用 socket.io (Websocket 通信)实现与前端的数据传输。

使用 xtermjs 实现网页上的终端组件,实现Linux终端命令、颜色等显示。

基础流程图如下:

核心代码

既然方案已经有了,那么就可以实现方案,核心代码大概是这样。

arduino 复制代码
// 注意:这只是筛选的部分核心代码,并非可直接运行的实现代码

// 初始化 HTTP 服务
const koaApp = koa.initKoa()
const httpServer = http.createServer(koaApp.callback())
httpServer.listen(config.port, config.ip)

// 初始化 Websocket 服务
const io = new Server(httpServer, {
  serveClient: false,
  pingInterval: 5000,
  pingTimeout: 5000,
  cookie: false,
  path: '/socket.io',
  cors: {
    origin: '*',
    methods: ['GET', 'POST', 'PUT', 'DELETE']
  }
})

// 创建子进程
const process = spawn('bash', [], {
  cwd: '.',
  stdio: 'pipe',
  windowsHide: true
})

// 监听子进程的输入输出流,并且监听退出事件,同步给前端进程状态
// io.emit 是 Socket.io 发送数据的方法
process.stdout.on('data', (text) => io.emit('instance/stdout', text))
process.stderr.on('data', (text) => io.emit('instance/stdout', text))
process.on('exit', (code) => io.emit('instance/exit', code))

前端我们先实现控制台组件

xml 复制代码
      <div id="terminal"></div>
      <script>
        var term = new Terminal();
        term.open(document.getElementById('terminal'));
        term.write('Hello$ ')
        // 这里还需要监听组件的按键事件,将按下的每一个键全部传递到后端
        // 注意不是以一行为单位传输,而是每一次按键。
      </script>

再实现Socket.io的连接与数据收发

javascript 复制代码
// Websocket 连接
const addr = 'ws://localhost:8080'
console.log('浏览器正在连接', addr)
const socket = io(addr, {}).connect()

socket.on('connect', () => {
  console.log('[WS->Server] Websocket 成功连接')
})

socket.on('disconnect', () => {
  console.log('[WS->Server] Websocket 连接断开')
})

//  将后端发来的程序输出流直接输出到 Term 组件
this.socket.on('instance/stdout', (packet) => {
  this.term.write(packet.data)
})

小结

这样,我们就基本实现了一个最最简单的 Web 终端,接下来通过改变启动进程的命令,就可以实现运行各种命令并且能够实时交互啦!

我们可以运行各种控制台程序在 Web 界面上,并且实现交互的功能。

模拟 TTY(teletypewriter)

什么是TTY(itsfoss.com/what-is-tty...)?为什么需要这玩意?

简单来说,模拟TTY就是虚拟一个真实的终端设备(上世纪那种古老的终端DOS显示器),来实现一个完整的虚拟控制台,从而可以在显示屏上播放图片,动画,色彩以及窗口等。

我们的实现原理是通过监听进程的输入输出流(stdin/stdout)来实现的,这是最简单的进程间通信模型,并非是一个完美的解决方案。

如果想在我们现在的 Web 控制台上播放高级的终端动画(比如复杂的进度条之类的),那单纯靠进程的输入输出是无法实现的,因为它没有"行"和"高"的概念,如果我们想实现真正的拥有高度和宽度的设备显示器控制台,就必须实现模拟TTY。

此时,我们的后端架构要变成这样,多一层 TTY 模拟。

核心代码实现

使用微软研发的 github.com/microsoft/n... 库完成这个需求。

php 复制代码
// 启动进程
var shell = os.platform() === 'win32' ? 'powershell.exe' : 'bash';

// 创建一个虚拟终端设备(TTY),并且设置高宽,并通过命令执行进程
var ptyProcess = pty.spawn(shell, [], {
  name: 'xterm-color',
  cols: 80,
  rows: 30,
  cwd: process.env.HOME,
  env: process.env
});

// 此时的数据输出包含了颜色代码,排版符号等各种数据。
// 可以实现在 Web 终端上播放特效以及光标等动态更新等。
ptyProcess.on('data', function(data) {
  // 发送给前端
  io.emit('instance/stdout', text)
});

// 向伪终端发送命令
ptyProcess.write('ls\r');

TTY 实现结果

只要实现TTY,我们就可以执行这种及其复杂的 Linux 程序了,可以说就是一个没有基于 SSH 客户端的一个模拟终端!

支持 Tab 补全,Ctrl,Alt,F1~F12 等功能键。

真实案例

有一个开源项目正是使用了这种设计方案,有兴趣的小伙伴可以参考哦,此项目还有更多设计方案可以供各位学习使用,喜欢的小伙伴可以点个星星。

MCSManager/MCSManager: Distributed, Docker-supported, out-of-the-box, and Lightweight control panel for Minecraft server and more. (github.com)

相关推荐
Amd79412 分钟前
Nuxt.js 应用中的 webpack:compiled 事件钩子
前端·webpack·开发·编译·nuxt.js·事件·钩子
生椰拿铁You20 分钟前
09 —— Webpack搭建开发环境
前端·webpack·node.js
狸克先生31 分钟前
如何用AI写小说(二):Gradio 超简单的网页前端交互
前端·人工智能·chatgpt·交互
baiduopenmap1 小时前
百度世界2024精选公开课:基于地图智能体的导航出行AI应用创新实践
前端·人工智能·百度地图
loooseFish1 小时前
小程序webview我爱死你了 小程序webview和H5通讯
前端
菜牙买菜1 小时前
让安卓也能玩出Element-Plus的表格效果
前端
请叫我欧皇i1 小时前
html本地离线引入vant和vue2(详细步骤)
开发语言·前端·javascript
533_1 小时前
[vue] 深拷贝 lodash cloneDeep
前端·javascript·vue.js
guokanglun1 小时前
空间数据存储格式GeoJSON
前端
zhang-zan2 小时前
nodejs操作selenium-webdriver
前端·javascript·selenium