实现网页版xshell,需要学习的东西有点多,下面一个个简单介绍
这是网上的一个开源框架,其作用主要是界面方面,比如新建一个小黑窗,设置各种样式等作用,用法也很简单,具体可查https://xtermjs.org/
express是一个开源的框架,大多数公司也在使用这样的框架作为Node中间层或者是服务端使用,可以快速搭建一个服务端出来,
var express = require('express'); var app = express(); app.get('/', function(req, res){ res.send(' Hello World! '); }); app.listen(3000);
使用浏览器访问 http://localhost:3000 看到 Hello World! 表示启动成功
其可以设置各种访问路径,请求方式,以及融合其他开源框架
WebSocket 是 HTML5 开始提供的一种浏览器与服务器间进行全双工通讯的网络技术。 WebSocket 通信协议于2011年被IETF定为标准RFC 6455,WebSocketAPI 被 W3C 定为标准。 在 WebSocket API 中,浏览器和服务器只需要要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
一旦建立连接(直到断开或者出错),服务端与客户端握手后则一直保持连接状态,是持久化连接;这个都比较熟悉不多说
ssh2是专门为了连接服务器开发的开源框架,具体可看https://github.com/mscdex/ssh2
//首先调用客户端组件 <SSHClient host={params.host} username={params.username} password={params.password} port={params.port}/>
//SSHClient import React, { useEffect, useState,FunctionComponent } from 'react'; import { Terminal } from 'xterm'; import 'xterm/css/xterm.css'; type Props = {//四个参数传过来,这是你需要连接的服务器的信息。 host?:string; port?:number; username?:string; password?:string; } const WebTerminal :FunctionComponent<Props> = (props) => { const {host,port,username,password} = props const [webTerminal, setWebTerminal] = useState<Terminal | null>(null); const [ws, setWs] = useState<WebSocket | null>(null); useEffect(() => { // 新增监听事件 if (webTerminal && ws) { // 监听 webTerminal.onKey(e => { const { key } = e; ws.send(key); }); // ws监听 ws.onmessage = e => { console.log(e); if (webTerminal) { if (typeof e.data === 'string') { webTerminal.write(e.data); } else { console.error('格式错误'); } } }; } }, [webTerminal, ws]); useEffect(() => { // 初始化终端 const ele = document.getElementById('terminal'); while(ele && ele.hasChildNodes()){ //当table下还存在子节点时 循环继续 //这里是为了参数输错的情况下,从新改正参数,点击连接,新建一个新的窗口 ele && ele.firstChild && ele.removeChild(ele.firstChild); } if (ele) { // 初始化 const terminal = new Terminal({ cursorBlink: true, cols: 175, rows: 40, }); terminal.focus(); terminal.onKey(e => { // terminal.write(e.key); if (e.key== '\r') { // terminal.write('\nroot\x1b[33m$\x1b[0m'); } else if (e.key== '\x7F') { terminal.write('\b \b'); } }); terminal.open(ele); terminal.write('连接中....'); setWebTerminal(terminal); } // 初始化ws连接 if (ws) ws.close(); const socket = new WebSocket('ws://127.0.0.1:3888'); socket.onopen = () => {//和服务端建立socket连接 let message = { host:host, port:port, username:username, password:password }; socket.send(JSON.stringify(message)); }; setWs(socket); }, [host,port,username,password]); return <div id="terminal" />; }; export default WebTerminal; //直接跟随项目启动就行
const express = require('express'); const app = express(); const expressWs = require('express-ws')(app); const SSHClient = require('ssh2').Client; const utf8 = require('utf8'); const createNewServer = (machineConfig, socket) => { const ssh = new SSHClient(); const { host, username, password,port } = machineConfig; // 连接成功 ssh.on('ready', function () { //准备就绪,然后建立ssh连接 socket.send('\r\nSSH 连接成功 \r\n'); ssh.shell(function (err, stream) { // 出错 if (err) { return socket.send('\r\nSSH连接失败: ' + err.message + '\r\n'); } // 前端发送消息 socket.on('message', function (data) { stream.write(data); }); // 通过sh发送消息给前端 stream.on('data', function (d) { socket.send(utf8.decode(d.toString('binary'))); // 关闭连接 }).on('close', function () { ssh.end(); }); }) // 关闭连接 }).on('close', function () { socket.send('\r\nSSH连接关闭 \r\n'); // 连接错误 }).on('error', function (err) { socket.send('\r\nSSH连接失败: ' + err.message); // 连接 }).connect({ port, host, username, password }); } const isJSON = (str) => { //判断是不是json,不然容易报错,这个服务就挂了 if (typeof str == 'string') { try { JSON.parse(str); return true; } catch(e) { // console.log(str); return false; } } console.log('It is not a string!') } app.ws('/', (ws, req) => { //建立连接 ws.on("message", (data) => { //建立连接后获取客户端发过来的地址等信息 try { isJSON(data) && createNewServer({ port: JSON.parse(data).port, host: JSON.parse(data).host, username: JSON.parse(data).username, password: JSON.parse(data).password }, ws) } catch(e) { console.log(e); } }); }); app.listen(3888,()=>{ console.log('3888 port is listening') })