原理 客户端使用xterm.js展示命令行,服务端使用ssh2.js连接服务器,服务端与客户端通过sock进行通信
版本 xterm.js@3.12.0 ssh2.js@0.8.9 socket.io@2.3.0 相关代码 https://github.com/blogwy/vue-web-shell
客户端 // 初始化Terminal const term = new Terminal({ cursorBlink: true }) term.open(document.getElementById('terminal')) term.fit() // 启动socket服务 const socket = openSocket('http://192.168.1.105:3100/ssh') socket.on('connect', () => { console.log('---连接成功---') console.log(`---socket.id:${socket.id}---`) socket.emit('init_data', { ip: '000.0.000.00', username: 'root', password: '00000' }) }) // 监听Terminal输入,把输入命令通过socket发送到服务端 term.on('data', res => { socket.emit('ssh_client_data', res) }) // 监听服务端返回的命令运行结果,显示到Terminal中 socket.on('ssh_server_data', res => { term.write(res) }) 服务端 const app = require('express')(); const http = require('http').createServer(app); const io = require('socket.io')(http); const sshNamespace = io.of('/ssh') const SSHClient = require('ssh2').Client; const ssh = new SSHClient(); const utf8 = require('utf8'); sshNamespace.on('connection', socket => { console.log('socket.id:', socket.id) socket.on('init_data', res => { console.log(res) // 拿到ip数据,初始化连接 initSSH(socket, res) }) }) http.listen(3100, () => { console.log('listening on http://localhost:3100'); }); function initSSH (socket, config) { console.log(config) ssh.on('ready', () => { ssh.shell((err, stream) => { if (err) { socket.emit('shell_error', '\r\n*** SSH SHELL ERROR: ' + err.message + ' ***\r\n'); } // 监听客户端发送的命令 socket.on('ssh_client_data', data => { stream.write(data); }); // 监听返回结果并emit到客户端 stream.on('data', d => { socket.emit('ssh_server_data', utf8.decode(d.toString('binary'))); }).on('close', () => { console.log('close'); ssh.end(); }); }); }).on('close', () => { socket.emit('connect_closed', '\r\n*** SSH CONNECTION CLOSED ***\r\n'); }).on('error', err => { console.log(err); socket.emit('connect_error', '\r\n*** SSH CONNECTION ERROR: ' + err.message + ' ***\r\n'); }).connect({ host: config.ip, port: 22, username: config.username, password: config.password }); }