实现在 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)

相关推荐
前端老宋Running7 分钟前
一次从“卡顿地狱”到“丝般顺滑”的 React 搜索优化实战
前端·react.js·掘金日报
隔壁的大叔7 分钟前
如何自己构建一个Markdown增量渲染器
前端·javascript
用户4445543654269 分钟前
Android的自定义View
前端
WILLF10 分钟前
HTML iframe 标签
前端·javascript
枫,为落叶27 分钟前
Axios使用教程(一)
前端
小章鱼学前端32 分钟前
2025 年最新 Fabric.js 实战:一个完整可上线的图片选区标注组件(含全部源码).
前端·vue.js
ohyeah33 分钟前
JavaScript 词法作用域、作用域链与闭包:从代码看机制
前端·javascript
流星稍逝35 分钟前
手搓一个简简单单进度条
前端
倚栏听风雨1 小时前
详解 TypeScript 中,async 和 await
前端
小皮虾1 小时前
告别服务器!小程序纯前端“图片转 PDF”工具,隐私安全又高效
前端·javascript·微信小程序