使用java代码使用sftp和ssh协议实现一台Linux服务器远程操作多台 踩的坑

使用java代码使用sftp和ssh协议实现一台Linux服务器远程操作多台 踩的坑

需求说明

  1. 在一台Linux服务器(作为主服务器)上部署java代码,实现一台对多台(子)服务器的交互,完成文件传输和命令的操作(如 查询、进程的kill,java命令的操作等)
  2. 不可以远程连接使用root用户权限,各个连接的服务器需创建新用户(tester)去访问;

常规操作

  1. linux创建新用户–不赘述
  2. 网上sftp协议(实现文件下载 上传)和 ssh协议(实现)的代码大把的 这里提供两个(见下方)

踩的坑

  1. 主服务器ssh远程不到子服务器
  2. 遍历一个ip的字符串集合 List,连接了当前ip,进行的操作却是执行了上一个ip的数据;
  3. 远程代码执行 kill 命令操作 执行失败;
  4. 远程代码执行 java -jar 命令操作jar包,执行失败,且卡在执行java -jar 命令的代码一行 不再往下执行其他代码;

坑1 :主服务器ssh远程不到子服务器,远程到了 也执行不了命令
操作:
远程连接到子服务器:
方法1:需要输入用户密码
ssh -p 端口号 用户名@IP地址
如 :ssh -p 22 tester@10.10.10.10
方法2:不需要二次输入密码
sshpass -p 用户密码 ssh -P -o StrictHostKeyChecking=no -p 端口号 用户名@IP地址
如:sshpass -p a12345 ssh -P -o StrictHostKeyChecking=no -p 22 tester@10.10.10.10
解决:
在子服务器下主服务器ip添加至白名单即可:
vi /etc/hosts.allow
在最后一行加入主服务器的ip:内容如下
sshd:主服务器IP
如:sshd:10.10.10.10

远程到了代码也执行不了ssh操作的解决:
原因:用户权限不足,在子服务器添加用户权限
解决:在子服务器中执行如下命令
1.切换到root用户下,怎么切换就不用说了吧,不会的自己百度去.
2.添加sudo文件的写权限,命令是:
chmod u+w /etc/sudoers
3.编辑sudoers文件
vi /etc/sudoers
找到这行 root ALL=(ALL) ALL,在他下面添加xxx ALL=(ALL) ALL (这里的xxx是你的用户名)

ps:这里说下你可以sudoers添加下面四行中任意一条
youuser ALL=(ALL) ALL
%youuser ALL=(ALL) ALL
tester ALL=(ALL) NOPASSWD: ALL
%youuser ALL=(ALL) NOPASSWD: ALL

第一行:允许用户youuser执行sudo命令(需要输入密码).
第二行:允许用户组youuser里面的用户执行sudo命令(需要输入密码).
第三行:允许用户tester执行sudo命令,并且在执行的时候不输入密码.
第四行:允许用户组youuser里面的用户执行sudo命令,并且在执行的时候不输入密码.

4.撤销sudoers文件写权限,命令:
chmod u-w /etc/sudoers

这样普通用户就可以使用sudo了
资源摘抄于 https://www.cnblogs.com/xiaochaoyxc/p/6206481.html

坑2 :遍历一个ip的字符串集合 List,连接了当前ip,进行的操作却是执行了上一个ip的数据;
解决:
SFTPUtils类中的getInstance()方法 实例化对象 ,连接下一个ip服务器后未重新创建,改为下方的即可; 每次连接都创建新的对象。(可再考虑优化);

	//获取实例化对象
    public static SFTPUtils getInstance(String host, int port, String username, String password) {
        SFTPUtils instance = new SFTPUtils();//创建连接对象
        sftp = instance.connect(host, port, username, password);   //获取连接
        return instance;
    }

SSHUtils类同理 代码中已更改。

坑3 :远程代码执行 kill 命令操作 执行失败;
解决:
由于我远程连接的不是root用户,新创建的一个测试用户tester无root权限 需要使用sudo kill + 进程号

坑4: 远程代码执行 java -jar 命令操作jar包,执行失败,且卡在执行java -jar 命令的代码一行 不再往下执行其他代码;
解决:(其实最后也没有解决,只是找到了问题 跳过了问题)
使用ssh协议执行java -jar ,命令时发现 代码卡着不走了,也没报错,但是发现java命令确实已经运行了,最后一点一点找 发现是因为我们执行linux的命令时候往往需要获取命令执行的返回值,代码中命令执行后 ,把返回结果转化为IO流后返回 ,java -jar命令的运行就是在这里出了问题,如下两行代码:

            InputStream stdout = new StreamGobbler(openSession.getStdout());
            out = IOUtils.toString(stdout, StandardCharsets.UTF_8);

执行java -jar命令时候删除这两行代码运行 即可!(投机取巧,博主未真正解决问题)

代码如下:(仅供参考)

添加maven依赖

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.28</version>
    </dependency>

    <dependency>
      <groupId>ch.ethz.ganymed</groupId>
      <artifactId>ganymed-ssh2</artifactId>
      <version>262</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.jcraft/jsch -->
    <dependency>
      <groupId>com.jcraft</groupId>
      <artifactId>jsch</artifactId>
      <version>0.1.55</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.7.21</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>1.7.21</version>
    </dependency>
    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>1.2</version>
    </dependency>
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.5</version>
    </dependency>

sftp协议


import com.jcraft.jsch.*;
import com.jcraft.jsch.ChannelSftp.LsEntry;
import org.apache.logging.log4j.Logger;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Properties;
import java.util.Vector;


/**
 * SFTP
 */
public class SFTPUtils {

    private static final Logger LOG = org.apache.logging.log4j.LogManager.getLogger(SFTPUtils.class);

    private static ChannelSftp sftp;

    private SFTPUtils() {
    }
    
	//获取实例化对象
    public static SFTPUtils getInstance(String host, int port, String username, String password) {
        if (instance == null) {
            if (instance == null) {
                instance = new SFTPUtils();
                sftp = instance.connect(host, port, username, password);   //获取连接
            }
        }
        return instance;
    }

    /**
     * 连接sftp服务器
     *
     * @param host     主机
     * @param port     端口
     * @param username 用户名
     * @param password 密码
     * @return
     */
    public ChannelSftp connect(String host, int port, String username, String password) {
        ChannelSftp sftp = null;
        try {
            JSch jsch = new JSch();
            jsch.getSession(username, host, port);
            Session sshSession = jsch.getSession(username, host, port);
            sshSession.setPassword(password);
            Properties sshConfig = new Properties();
            sshConfig.put("StrictHostKeyChecking", "no");
            sshSession.setConfig(sshConfig);
            sshSession.connect();
            LOG.info("SFTP Session connected.");
            Channel channel = sshSession.openChannel("sftp");
            channel.connect();
            sftp = (ChannelSftp) channel;
            LOG.info("Connected to " + host);
        } catch (Exception e) {
            LOG.error(e.getMessage());
        }
        return sftp;
    }

    /**
     * 上传文件
     *
     * @param directory  上传的目录
     * @param uploadFile 要上传的文件
     */
    public boolean upload(String directory, String uploadFile) {
        try {
            sftp.cd(directory);
            File file = new File(uploadFile);
            FileInputStream fileInputStream = new FileInputStream(file);
            sftp.put(fileInputStream, file.getName());
            fileInputStream.close();
            return true;
        } catch (Exception e) {
            LOG.error(e.getMessage());
            return false;
        }
    }

    /**
     * 下载文件
     *
     * @param directory    下载目录
     * @param downloadFile 下载的文件
     * @param saveFile     存在本地的路径
     */
    public File download(String directory, String downloadFile, String saveFile) {
        try {
            sftp.cd(directory);
            File file = new File(saveFile);
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            sftp.get(downloadFile, fileOutputStream);
            fileOutputStream.close();
            return file;
        } catch (Exception e) {
            LOG.error(e.getMessage());
            return null;
        }
    }

    /**
     * 下载文件
     *
     * @param downloadFilePath 下载的文件完整目录
     * @param saveFile     存在本地的路径
     */
    public File download(String downloadFilePath, String saveFile) {
        try {
            int i = downloadFilePath.lastIndexOf('/');
            if (i == -1)
                return null;
            sftp.cd(downloadFilePath.substring(0, i));
            File file = new File(saveFile);
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            sftp.get(downloadFilePath.substring(i + 1), fileOutputStream);
            fileOutputStream.close();
            return file;
        } catch (Exception e) {
            LOG.error(e.getMessage());
            return null;
        }
    }

    /**
     * 删除文件
     *
     * @param directory  要删除文件所在目录
     * @param deleteFile 要删除的文件
     */
    public void delete(String directory, String deleteFile) {
        try {
            sftp.cd(directory);
            sftp.rm(deleteFile);
        } catch (Exception e) {
            LOG.error(e.getMessage());
        }
    }

    /**
     * 断开连接
     */
    public void disconnect() {
        try {
            sftp.getSession().disconnect();
        } catch (JSchException e) {
            LOG.error(e.getMessage());
        }
        sftp.quit();
        sftp.disconnect();
    }

    /**
     * 列出目录下的文件
     *
     * @param directory 要列出的目录
     * @throws SftpException
     */
    public Vector<LsEntry> listFiles(String directory) throws SftpException {
        return sftp.ls(directory);
    }
}

SSH协议


import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.Session;
import ch.ethz.ssh2.StreamGobbler;
import org.apache.commons.io.IOUtils;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;

public class SSHUtils {

    private static Connection conn = null;

//    private static final String baseDir = "/work/Apk_Release/KeKeUserCenter";

    public static Connection getSSHConnection(String ip, int port, String user, String password) {
        try {
            conn = new Connection(ip, port);
            conn.connect();
            synchronized (conn){
                if(!conn.isAuthenticationComplete()) {
                    if (conn.authenticateWithPassword(user, password)) {
                        System.out.println("连接" + ip + ",成功");
                    }
                }
            }
        } catch (IOException e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
        return conn;
    }

    public static boolean closeSSHConnection() {
        if (conn != null) {
            conn.close();
            return true;
        }
        return false;
    }

    public static void exeJavaCommand(String ip, int port, String user, String password, String command){
        Connection conn;

        try {
            //连接服务器
            conn = getSSHConnection(ip, port, user, password);
            Session openSession = conn.openSession();
            //执行命令
            openSession.execCommand(command);

//            InputStream stdout = new StreamGobbler(openSession.getStdout());
//            out = IOUtils.toString(stdout, StandardCharsets.UTF_8);

        } catch (IOException e) {
            e.printStackTrace(System.err);
        } finally {
            if (closeSSHConnection()) {
                conn = null;
                System.out.println("断开连接成功");
            }else {
                System.out.println("断开连接失败");
            }
        }
    }

    public static String exeCommand(String ip, int port, String user, String password, String command){
        Connection conn;
        String out = null;
        try {
            //连接服务器
            conn = getSSHConnection(ip, port, user, password);
            Session openSession = conn.openSession();
            //执行命令
            openSession.execCommand(command);

            InputStream stdout = new StreamGobbler(openSession.getStdout());
            out = IOUtils.toString(stdout, StandardCharsets.UTF_8);

        } catch (IOException e) {
            e.printStackTrace(System.err);
        } finally {
            if (closeSSHConnection()){
                conn = null;
                System.out.println("断开连接成功");
            }else {
                System.out.println("断开连接失败");
            }
        }
        return out;
    }
}

有不足之处,望多多指点!感谢!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值