其他分享
首页 > 其他分享> > 基于Express+xterm.js的WebSSH

基于Express+xterm.js的WebSSH

作者:互联网

源文档地址:基于Express的WebSSH

后端基于基于nodeexpressssh2websocket

前端基于reactxterm.js

1. 服务端

1.1 下载npm

yarn add express-ws ssh2 utf8

1.2 服务端代码

src/utils/createNewServer.ts

const SSHClient = require('ssh2').Client;
const utf8 = require('utf8');


export const createNewServer = (machineConfig: any, socket: any) => {
  const ssh = new SSHClient();
  const { host, username, password } = machineConfig;
  // 连接成功
  ssh.on('ready', function () {

    socket.send('\r\n*** SSH CONNECTION SUCCESS ***\r\n');

    ssh.shell(function (err: any, stream: any) {
      // 出错
      if (err) {
        return socket.send('\r\n*** SSH SHELL ERROR: ' + err.message + ' ***\r\n');
      }

      // 前端发送消息
      socket.on('message', function (data: any) {
        stream.write(data);
      });

      // 通过sh发送消息给前端
      stream.on('data', function (d: any) {
        socket.send(utf8.decode(d.toString('binary')));

        // 关闭连接
      }).on('close', function () {
        ssh.end();
      });
    })

    // 关闭连接
  }).on('close', function () {
    socket.send('\r\n*** SSH CONNECTION CLOSED ***\r\n');

    // 连接错误
  }).on('error', function (err: any) {
    socket.send('\r\n*** SSH CONNECTION ERROR: ' + err.message + ' ***\r\n');

    // 连接
  }).connect({
    port: 22,
    host,
    username,
    password
  });
}

src/main.ts

const express = require('express');
const app = express();
const expressWs = require('express-ws')(app);

import { createNewServer } from './utils/createNewServer';


app.get('/', function (req: any, res: any, next: any) {
  res.end();
});

app.ws('/', function (ws: any, req: any) {
  createNewServer({
    host: '192.168.2.94',
    username: 'megaium',
    password: 'Megaium!'
  }, ws)
});

app.listen(3000)

2. 客户端

2.1 客户端代码

*.ts

import React, { useEffect, useState } from 'react';
import { Terminal } from 'xterm';
import { WebLinksAddon } from 'xterm-addon-web-links';
import { FitAddon } from 'xterm-addon-fit';

import 'xterm/css/xterm.css';
import styles from './index.less';

const FontSize: number = 14;
const Col = 80;

const WebTerminal = () => {
  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');
    if (ele) {
      const height = ele.clientHeight;
      // 初始化
      const terminal = new Terminal({
        cursorBlink: true,
        cols: Col,
        rows: Math.ceil(height / FontSize),
      });

      // 辅助
      const fitAddon = new FitAddon();
      terminal.loadAddon(new WebLinksAddon());
      terminal.loadAddon(fitAddon);

      terminal.open(ele);
      terminal.write('Hello from \x1B[1;3;31mxterm.js\x1B[0m $ ');
      fitAddon.fit();
      setWebTerminal(terminal);
    }

    // 初始化ws连接
    if (ws) ws.close();

    const socket = new WebSocket('ws://192.168.2.123:3000');
    socket.onopen = () => {
      socket.send('connect success');
    };

    setWs(socket);
  }, []);

  return <div id="terminal" className={styles.main} />;
};

export default WebTerminal;

3. 效果

web-ssh

标签:function,xterm,const,socket,WebSSH,Express,send,ws,any
来源: https://blog.csdn.net/jx950915/article/details/111555974