美文网首页
react 版 xterm+node 实现webssh

react 版 xterm+node 实现webssh

作者: 小碎步快跑 | 来源:发表于2024-01-02 17:41 被阅读0次

    前端使用xterm通过socket.io-client和后端通信,后端使用nodejs+utf8+socket.io+ssh2

    实现效果如下:

    22.png

    前端代码:

    前端主要依赖包:xterm、 xterm-addon-fit、 socket.io-client

    react组件:

    import "xterm/css/xterm.css";
    import io from "socket.io-client";
    import { Terminal } from "xterm";
    import { FitAddon } from "xterm-addon-fit";
    import { Form, Input, Button } from "antd";
    import "./index.less";
    
    function WebShell({ host }) {
      const { Item } = Form;
      const [term, setTerm] = useState();
      const [socket, setSocket] = useState();
      const fitAddonRef = useRef(null);
    
      const addTerm = (val) => {
        if (!val.username) {
          return;
        }
        setTerm(null);
        const termInstance = new Terminal({
          cursorBlink: true,
          scrollback: 50,
        });
        setTerm(termInstance);
        const fitAddon = new FitAddon();
        fitAddonRef.current = fitAddon;
        document.querySelector(".termbox").innerHTML = "";
        termInstance.open(document.querySelector(".termbox"));
        termInstance.loadAddon(fitAddon);
        fitAddon.fit();
        termInstance.focus();
    
        socket.emit("createNewServer", {
          msgId: "termbox",
          ip: host,
          username: val.username,
          password: val.password,
          cols: 100,
          rows: 20,
        });
    
        termInstance.onData((data) => {
          console.log(data);
          socket.emit("termbox", data);
        });
    
        socket.on("termbox", (data) => {
          termInstance.write(data);
        });
    
        // window.addEventListener(
        //   "resize",
        //   () => {
        //     fitAddon.fit();
        //     socket.emit("resize", {
        //       cols: 100,
        //       rows: 20,
        //     });
        //   },
        //   false
        // );
      };
    
      useEffect(() => {
        const socketInstance = io("http://XXXX:5000");
        setSocket(socketInstance);
      }, []);
    
      return (
        <div className="app-container">
          <Form
            className="query-form"
            labelCol={{ span: 4 }}
            wrapperCol={{ span: 16 }}
            onFinish={addTerm}
            initialValues={{
              host: host, // 设置默认值
            }}
          >
            <Item label="地址" name="host">
              <Input disabled />
            </Item>
            <Item label="用户名" name="username">
              <Input />
            </Item>
            <Item label="密码" name="password">
              <Input.Password />
            </Item>
            <Button type="primary" htmlType="submit">
              连接
            </Button>
          </Form>
          <div
            style={{
              flex: 1,
              display: "flex",
              paddingBottom: "10px",
              marginTop: "10px",
            }}
          >
            <div
              style={{ paddingLeft: "10px", paddingRight: "10px" }}
              ref={fitAddonRef}
              className="termbox"
            ></div>
          </div>
        </div>
      );
    }
    
    export default WebShell;
    
    

    index.less

    .termbox {
      flex: 1;
      width: 100%;
      height: 100%;
      padding: 0 1rem;
    }
    
    

    后端代码

    1、先创建一个文件夹npm init 一个新项目
    2、安装依赖express 、utf8、socket.io、ssh2
    3、index.js里面代码如下
    4、启动服务 node ./index.js

    var app = require('express')();
    /**用来实现多个webssh功能**/
    const http = require('http').Server(app);
    const io = require('socket.io')(http, {cors: true});
    const utf8 = require('utf8');
    const SSHClient = require('ssh2').Client;
    
    
    function createNewServer(machineConfig, socket) {
      var ssh = new SSHClient();
      let {msgId, ip, username, password} = machineConfig;
      ssh
        .on('ready', function () {
          socket.emit(msgId, '\r\n*** ' + ip + ' SSH CONNECTION ESTABLISHED ***\r\n');
          // ssh设置cols和rows处理界面输入字符过长显示问题
          ssh.shell({cols: machineConfig.cols, rows: machineConfig.rows}, function (err, stream) {
            if (err) {
              return socket.emit(msgId, '\r\n*** SSH SHELL ERROR: ' + err.message + ' ***\r\n');
            }
            socket.on(msgId, function (data) {
              stream.write(data);
            });
            stream.on('data', function (d) {
              socket.emit(msgId, utf8.decode(d.toString('binary')));
            }).on('close', function () {
              ssh.end();
            });
            socket.on('resize', function socketOnResize (data) {
              stream.setWindow(data.rows, data.cols);
            });
          })
        })
        .on('close', function () {
          socket.emit(msgId, '\r\n*** SSH CONNECTION CLOSED ***\r\n');
        })
        .on('error', function (err) {
          console.log(err);
          socket.emit(msgId, '\r\n*** SSH CONNECTION ERROR: ' + err.message + ' ***\r\n');
        }).connect({
          host: ip,
          port: 22,
          username: username,
          password: password
      });
    }
    
    io.on('connection', function (socket) {
      socket.on('createNewServer', function (machineConfig) {
        // 新建一个ssh连接
        console.log("createNewServer")
        createNewServer(machineConfig, socket);
      })
    
      socket.on('disconnect', function () {
        console.log('user disconnected');
      });
    })
    
    http.listen(5000, function () {
      console.log('listening on * 5000');
    });
    

    相关文章

      网友评论

          本文标题:react 版 xterm+node 实现webssh

          本文链接:https://www.haomeiwen.com/subject/scapndtx.html