ssh应用- linux服务器A登陆linux服务器B

470 阅读3分钟

实际背景

在日常工作中, 大家难免会遇到这样一种情况, 就是我需要先登陆一台linux服务器A, 然后从A登陆到另一台linux服务器B.

这么设计的目的一般都是出于安全的考虑, 将可以线下直接访问的服务器和提供服务的服务器隔离开, 同时也能防范一些攻击. 但是这种设计对于正常使用也会带来一些麻烦, 因此期望某些设计能够帮助我们更方便的使用.

ssh 命令行直接登陆

假设我们命令终端可以访问到的机器是A, 也就代表A是能够被公司内网访问到, 我们的目标服务器是B, 那么我们可以在服务器A上提供一个web服务, 然后通过接口的方式直接访问B服务器的内容, 具体思路如下:

核心思路:

在服务器A上 可以通过ssh 命令直接登陆到服务器B上, 那么就可以直接通过命令行的形式直接在B服务器执行相应命令.

在A服务器执行如下命令:

ssh B服务器名 "具体命令"

注意: 具体命令是被包括在双引号中, 如果命令中还有单双引号或者/等特殊符号, 一定要注意转义

java代码如下:

            String [] cmdArray = new String[] {"/bin/sh", "-c", finalCmd};
            process = Runtime.getRuntime().exec(cmdArray);

正常的返回可以通过process.getInputStream()得到

异常信息的返回可以通过process.getErrorStream()得到

优点

  1. 你在A服务器ssh 登陆B服务器后, 能正常执行的命令, 按道理都可以通过这种方式用java代码实现, 验证起来十分方便

  2. 开发简单, 输入返回都可以由你的服务进行一定程度的控制和处理

  3. 可以自动加载目标服务器上的环境变量.

缺点

  1. 部分命令可能需要跟终端有所交互(不是指输入一些参数的交互, 而是有些命令会输出结果到特定位置例如输出到 /dev/tty了), 通过这种方式会导致无法正常返回, 需要特别处理

  2. 每一次请求代表一个命令, 代表新建一条ssh链接, 结束后断开, 无法保持链接, 因此不适用于一次连接执行多条命令或者高并发的情况.

利用jsch工具建立链接

如果期望建立一次链接, 执行多条命令的情况, 就要借助一些第三方依赖包来实现了, 我这里选用的是 com.jcraft.jsch包, 类似功能的包还有几个, 可以根据需要选用

核心思路没有什么变化, 只不过在建立连接和执行命令的时候 是通过jsch包提供的功能

maven依赖

    <dependency>
      <groupId>com.jcraft</groupId>
      <artifactId>jsch</artifactId>
      <version>0.1.53</version>
    </dependency>

java代码实现如下

public void jsch() throws JSchException, IOException {

        List<String> stdout = new ArrayList<>();
        JSch jsch = new JSch();
        Session session = jsch.getSession("user", "host", 222);
        session.setPassword("password");
        session.connect(5000);

        //打开通道,设置通道类型,和执行的命令
        Channel channel = session.openChannel("exec");
        ChannelExec channelExec = (ChannelExec)channel;
        channelExec.setCommand("ls");
        channelExec.setInputStream(null);
        BufferedReader input = new BufferedReader(new InputStreamReader(channelExec.getInputStream()));
        channelExec.connect();

        //接收远程服务器执行命令的结果
        String line;
        while ((line = input.readLine()) != null)
        {
            stdout.add(line);
        }
        input.close();

        //关闭通道
        channelExec.disconnect();
        //关闭session
        session.disconnect();

        LOGGER.info("执行命令返回 :" + stdout.toString());

    }

优点

  1. ssh连接可以通过工具保持, 适合命令频繁执行的情况, 可以减少不必要的ssh链接建立关闭的消耗

  2. 各种api接口功能比较齐全, 复杂度不高

  3. 支持拉取服务器文件

缺点

  1. 在认证方面有一些坑, 需要根据遇见的情况自己填一下

  2. 执行时无法获取到目标服务器的环境变量, 因此执行命令的时候 需要用命令的全路径. 例如xxxx/xxx/xxx/bin/java -jar , 直接使用java -jar 是不行的, 可以通过type命令获得命令的路径