To realize the web version of xshell, you need to learn a little more. The following is a brief introduction
Xterm.js
This is an open source framework on the Internet. Its main function is the interface, such as creating a new small black window and setting various styles. The usage is also very simple and specific https://xtermjs.org/
experss
express is an open source framework. Most companies are also using this framework as the Node middle tier or server, which can quickly build a server,
var express = require('express'); var app = express(); app.get('/', function(req, res){ res.send(' Hello World! '); }); app.listen(3000);
Access with browser http://localhost:3000 See Hello World! Indicates successful startup
It can set various access paths, request methods, and integrate other open source frameworks
websocket
WebSocket is a network technology for full duplex communication between browser and server provided by HTML5. WebSocket communication protocol was set as standard RFC 6455 by IETF in 2011, and WebSocket API was set as standard by W3C. In the WebSocket API, the browser and server only need to shake hands, and then a fast channel is formed between the browser and the server. The two can directly transmit data to each other.
Once a connection is established (until it is disconnected or an error occurs), the server will always maintain the connection state after shaking hands with the client, which is a persistent connection; I'm familiar with this. I don't say much
ssh2
SSH2 is an open source framework developed specifically for connecting servers. See https://github.com/mscdex/ssh2
Interface
code
Client code
//Call the client component first <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 = {//Pass the four parameters, which are the information of the server you need to connect to. 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(() => { // Add listening event if (webTerminal && ws) { // monitor webTerminal.onKey(e => { const { key } = e; ws.send(key); }); // ws listening ws.onmessage = e => { console.log(e); if (webTerminal) { if (typeof e.data === 'string') { webTerminal.write(e.data); } else { console.error('Format error'); } } }; } }, [webTerminal, ws]); useEffect(() => { // Initialize terminal const ele = document.getElementById('terminal'); while(ele && ele.hasChildNodes()){ //When there are still child nodes under the table, the loop continues //This is to correct the parameter in case of wrong parameter input. Click Connect to create a new window ele && ele.firstChild && ele.removeChild(ele.firstChild); } if (ele) { // initialization 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('Connecting....'); setWebTerminal(terminal); } // Initialize ws connection if (ws) ws.close(); const socket = new WebSocket('ws://127.0.0.1:3888'); socket.onopen = () => {//Establish socket connection with the server 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; //Just follow the project launch
Server code
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; // Connection succeeded ssh.on('ready', function () { //Get ready and establish an ssh connection socket.send('\r\nSSH Connection succeeded \r\n'); ssh.shell(function (err, stream) { // error if (err) { return socket.send('\r\nSSH connection failed: ' + err.message + '\r\n'); } // Front end send message socket.on('message', function (data) { stream.write(data); }); // Send messages to the front end through sh stream.on('data', function (d) { socket.send(utf8.decode(d.toString('binary'))); // Close connection }).on('close', function () { ssh.end(); }); }) // Close connection }).on('close', function () { socket.send('\r\nSSH Connection closed \r\n'); // Connection error }).on('error', function (err) { socket.send('\r\nSSH connection failed: ' + err.message); // connect }).connect({ port, host, username, password }); } const isJSON = (str) => { //Judge whether it is json, otherwise it is easy to report errors, and the service will hang up 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) => { //Establish connection ws.on("message", (data) => { //After establishing the connection, obtain the address and other information sent by the client 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') })
explain
- The server needs to create a new project to start, otherwise it cannot start. After starting, test whether the websocket connection is connected. If it is connected, test whether the ssh server can be connected. The start command of the server is node server.js (that is, JS file name), and the client is started normally
- The connection requested by the client here is 127.0.0.1, because I run the client and server on the same computer. If not, I have to change the corresponding one