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

相关推荐
子兮曰1 小时前
async/await高级模式:async迭代器、错误边界与并发控制
前端·javascript·github
恋猫de小郭1 小时前
2026 Flutter VS React Native ,同时在 AI 时代 VS Native 开发,你没见过的版本
android·前端·flutter
GIS之路3 小时前
ArcGIS Pro 中的 Notebooks 入门
前端
IT_陈寒5 小时前
React状态管理终极对决:Redux vs Context API谁更胜一筹?
前端·人工智能·后端
Kagol6 小时前
TinyVue 支持 Skills 啦!现在你可以让 AI 使用 TinyVue 组件搭建项目
前端·agent·ai编程
柳杉6 小时前
从零打造 AI 全球趋势监测大屏
前端·javascript·aigc
simple_lau6 小时前
Cursor配置MasterGo MCP:一键读取设计稿生成高还原度前端代码
前端·javascript·vue.js
睡不着先生6 小时前
如何设计一个真正可扩展的表单生成器?
前端·javascript·vue.js
天蓝色的鱼鱼6 小时前
模块化与组件化:90%的前端开发者都没搞懂的本质区别
前端·架构·代码规范
明君879976 小时前
Flutter 如何给图片添加多行文字水印
前端·flutter