java使用jsch連接linux


由於項目需要使用java來linux進行管理,近一番查找,發現第三方jar包 jsch 可以輕松實現對linux的管理,(相關文檔及例子請訪問官網www.jcraft.com),故引進。

在網上搜索了一些資料參考並修改(資料來源地址一下子找不到了,有發現的請提醒加上),創建一個工具類,可以實現對linux上的基本操作及系統上文件的上傳和下載。

代碼如下:

 

/**
 * @description 用來創建與 linux 交互的會話,操作文件和執行 操作 命令
 * @date: 2016/7/25
 * @author: gongtao
 */
public class LinuxConnetionHelper {

    private static final org.slf4j.Logger log = LoggerFactory.getLogger(LinuxConnetionHelper.class);
    private static final int TIME_OUT = 5*60*1000; //設置超時為5分鍾
    private static final Map<String,Session> cache = new HashMap<>(); //session緩存

    public static SessionMonitor sessionMonitor;
    /**
     * 創建 連接,需手動關閉
     * @param host
     * @param userName
     * @param password
     * @param port
     * @throws JSchException
     */
    public static Session connect(String host,String userName,String password,int port) throws JSchException {
        //創建對象
        JSch jsch = new JSch();
        //創建會話
        Session session = jsch.getSession(userName,host, port);
        //輸入密碼
        session.setPassword(password);
        //配置信息
        Properties config = new Properties();
        //設置不用檢查hostKey
        //如果設置成“yes”,ssh就不會自動把計算機的密匙加入“$HOME/.ssh/known_hosts”文件,
        //並且一旦計算機的密匙發生了變化,就拒絕連接。
        config.setProperty("StrictHostKeyChecking", "no");
//        //默認值是 “yes” 此處是由於我們SFTP服務器的DNS解析有問題,則把UseDNS設置為“no”
//        config.put("UseDNS", "no");
        session.setConfig(config);
        //過期時間
        session.setTimeout(TIME_OUT);
        //建立連接
        session.connect();

        return session;
    }

    /**
     * 創建  連接,無需手動關閉
     * @param host
     * @param userName
     * @param password
     * @param port
     * @throws JSchException
     */
    public static Session longConnect(String host,String userName,String password,int port) throws JSchException {
        String key = host + userName + password + port;
        Session session = cache.get(key);
        if (session == null){
            //創建對象
            JSch jsch = new JSch();
            //創建會話
            session = jsch.getSession(userName,host, port);
            //輸入密碼
            session.setPassword(password);
            //配置信息
            Properties config = new Properties();
            //設置不用檢查hostKey
            //如果設置成“yes”,ssh就不會自動把計算機的密匙加入“$HOME/.ssh/known_hosts”文件,
            //並且一旦計算機的密匙發生了變化,就拒絕連接。
            config.setProperty("StrictHostKeyChecking", "no");
//        //默認值是 “yes” 此處是由於我們SFTP服務器的DNS解析有問題,則把UseDNS設置為“no”
//        config.put("UseDNS", "no");
            session.setConfig(config);
            //過期時間
            //session.setTimeout(TIME_OUT);
            //建立連接,此時會在linux上新建一個進程,timeout 並不會結束進程,只有調用disconnect()才會結束此進程
            session.connect();
            cache.put(key,session);
        }else{
            //判斷session是否失效
            if (testSessionIsDown(key)){
                //session is down
                //session 失去連接則清除
                closeLongSessionByKey(key);
                //重新生成session
                session = longConnect(host, userName, password, port);
            }
        }
        //創建定時器
        createSessionMonitor();
        return session;
    }

    /**
     * 銷毀 session
     * @param session
     */
    public static void close(Session session){
        if (session != null){
            session.disconnect();
        }
    }

    /**
     * 測試session是否失效
     * @param key
     * @return
     */
    public static boolean testSessionIsDown(String key){
        Session session = cache.get(key);
        if (session == null){
            return true;
        }
        ChannelExec channelExec = null;
        try {
            channelExec = openChannelExec(session);
            channelExec.setCommand("true");
            channelExec.connect();
            return false;
        }catch (Throwable e){
            //session is down
            return true;
        }finally {
            if (channelExec != null){
                channelExec.disconnect();
            }
        }
    }
    /**
     * 銷毀 session
     * @param key
     */
    public static synchronized void closeLongSessionByKey(String key){
        Session session = cache.get(key);
        if (session != null){
            session.disconnect();
            cache.remove(key);
        }
    }

    /**
     * 銷毀 session
     * @param session
     */
    public static void closeLongSessionBySession(Session session){
        Iterator iterator = cache.keySet().iterator();
        while (iterator.hasNext()){
            String key = (String)iterator.next();
            Session oldSession = cache.get(key);
            if (session == oldSession){
                session.disconnect();
                cache.remove(key);
                return;
            }
        }
    }
    /**
     * 創建一個 sftp 通道並建立連接
     * @param session
     * @return
     * @throws Exception
     */
    public static ChannelSftp openChannelSftp(Session session) throws Exception
    {
        ChannelSftp channelSftp = (ChannelSftp)session.openChannel("sftp");
        channelSftp.connect();
        return channelSftp;
    }

    /**
     * 關閉 sftp 通道
     * @param channelSftp
     * @throws Exception
     */
    public static void closeChannelSftp(ChannelSftp channelSftp)
    {
        if (channelSftp != null){
            channelSftp.disconnect();
        }
    }

    /**
     * 下載文件
     * @param remoteFile
     *          遠程服務器的文件路徑
     * @param localPath
     *          需要保存文件的本地路徑
     * @throws IOException
     * @throws SftpException
     */
    public static void downloadFile(Session session , String remoteFile, String localPath) throws Exception {
        ChannelSftp channelSftp = openChannelSftp(session);
        try {
            String remoteFilePath = remoteFile.substring(0, remoteFile.lastIndexOf("/"));
            String remoteFileName = remoteFile.substring(remoteFile.lastIndexOf("/") + 1,remoteFile.length());
            if(localPath.charAt(localPath.length() - 1) != '/'){
                localPath += '/';
            }
            File file = new File(localPath + remoteFileName);
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
                file.createNewFile();
            }
            OutputStream output = new FileOutputStream(file);
            try {
                channelSftp.cd(remoteFilePath);
                log.info("遠程服務器路徑:" + remoteFilePath);
                log.info("本地下載路徑:" + localPath + remoteFileName);
                SftpATTRS attrs = channelSftp.lstat(remoteFile);
                channelSftp.get(remoteFile, output, new FileSftpProgressMonitor(attrs.getSize()));
            }catch (Exception e){
                throw e;
            }finally {
                output.flush();
                output.close();
            }
        }catch (Exception e){
            throw e;
        }finally {
            closeChannelSftp(channelSftp);
        }
    }

    /**
     * 上傳文件
     * @param localFile
     *          本地文件路徑
     * @param remotePath
     *          遠程服務器路徑
     * @throws IOException
     * @throws SftpException
     */
    public static void uploadFile(Session session,String localFile,String remotePath) throws Exception {
        ChannelSftp channelSftp = openChannelSftp(session);
        String remoteFileName = localFile.substring(localFile.lastIndexOf("/") + 1, localFile.length());
        File file = new File(localFile);
        final InputStream input = new FileInputStream(file);
        try {
            channelSftp.cd(remotePath);
        }catch (SftpException e){
            String tempPath = null;
            try {
                tempPath = remotePath.substring(0, remotePath.lastIndexOf("/"));
                channelSftp.cd(tempPath);
            }catch (SftpException e1){
                channelSftp.mkdir(tempPath);
            }
            channelSftp.mkdir(remotePath);
            channelSftp.cd(remotePath);
        }
        log.info("遠程服務器路徑:" + remotePath);
        log.info("本地上傳路徑:" + localFile);
        try {
            channelSftp.put(input, remoteFileName, new FileSftpProgressMonitor(file.length()));
        }catch (Exception e){
            throw e;
        }finally {
            input.close();
            closeChannelSftp(channelSftp);
        }
    }

    /**
     * 文件上傳
     * @param session
     * @param inputStream
     * @param fileName
     * @param remotePath
     * @throws Exception
     */
    public static void uploadFile(Session session,InputStream inputStream,String fileName,String remotePath) throws Exception {
        ChannelSftp channelSftp = openChannelSftp(session);
        channelSftp.cd(remotePath);
        log.info("遠程服務器路徑:" + remotePath);
        try {
            channelSftp.put(inputStream, fileName,new FileSftpProgressMonitor(inputStream.available()));
        }catch (Exception e){
            throw e;
        }finally {
            inputStream.close();
            closeChannelSftp(channelSftp);
        }
    }

    /**
     * 獲取遠程服務器文件列表
     * @param session
     * @param remotePath
     *          遠程服務器路徑
     * @return
     * @throws SftpException
     */
    public static Vector listFiles(Session session,String remotePath) throws Exception {
        ChannelSftp channelSftp = openChannelSftp(session);
        try {
            Vector vector = channelSftp.ls(remotePath);
            return vector;
        }catch (Exception e){
            throw e;
        }finally {
            closeChannelSftp(channelSftp);
        }
    }

    /**
     * 刪除文件
     * @param session
     * @param remotePath
     * @param fileName
     * @throws Exception
     */
    public static void removeFile(Session session,String remotePath,String fileName) throws Exception{
        ChannelSftp channelSftp = openChannelSftp(session);
        try {
            channelSftp.cd(remotePath);
            channelSftp.rm(fileName);
        }catch (Exception e){
            throw e;
        }finally {
            closeChannelSftp(channelSftp);
        }
    }

    /**
     * 刪除文件夾
     * @param session
     * @param remotePath
     * @throws Exception
     */
    public static void removeDir(Session session,String remotePath) throws Exception{
        ChannelSftp channelSftp = openChannelSftp(session);
        try {
            if (remotePath.lastIndexOf("/") == remotePath.length() - 1){
                remotePath = remotePath.substring(0,remotePath.length() - 1);
            }
            String parentDir = remotePath.substring(0,remotePath.lastIndexOf("/") + 1);
            String rmDir = remotePath.substring(remotePath.lastIndexOf("/") + 1,remotePath.length());
            channelSftp.cd(parentDir);
            channelSftp.rmdir(rmDir);
        }catch (Exception e){
            throw e;
        }finally {
            closeChannelSftp(channelSftp);
        }
    }

    /**
     * 新建一個 exec 通道
     * @param session
     * @return
     * @throws JSchException
     */
    public static ChannelExec openChannelExec(Session session) throws JSchException {
        ChannelExec channelExec = (ChannelExec)session.openChannel("exec");
        return channelExec;
    }

    /**
     * 關閉 exec 通道
     * @param channelExec
     */
    public static void closeChannelExec(ChannelExec channelExec){
        if (channelExec != null){
            channelExec.disconnect();
        }
    }

    /**
     * 執行 腳本
     * @param session
     * @param cmd
     *          執行 .sh 腳本
     * @param charset
     *          字符格式
     * @return
     * @throws IOException
     * @throws JSchException
     */
    public static String[] execCmd(Session session,String cmd,String charset) throws Exception{
        //打開通道
        ChannelExec channelExec = openChannelExec(session);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ByteArrayOutputStream error = new ByteArrayOutputStream();
        channelExec.setCommand(cmd);
        channelExec.setOutputStream(out);
        channelExec.setErrStream(error);
        channelExec.connect();
        //確保能夠執行完成及響應所有數據
        Thread.sleep(10000);
        String[] msg = new String[2];
        msg[0] = new String(out.toByteArray(),charset);
        msg[1] = new String(error.toByteArray(),charset);
        out.close();
        error.close();
        //關閉通道
        closeChannelExec(channelExec);
        return msg;
    }

    /**
     * 創建一個交互式的 shell 通道
     * @param session
     * @return
     * @throws JSchException
     */
    public static ChannelShell openChannelShell(Session session) throws JSchException{
        ChannelShell channelShell = (ChannelShell)session.openChannel("shell");
        return channelShell;
    }

    /**
     * 關閉 shell 通道
     * @param channelShell
     */
    public static void closeChannelShell(ChannelShell channelShell){
        if (channelShell != null){
            channelShell.disconnect();
        }
    }

    /**
     * 執行命令
     * @param cmds
     *          命令參數
     * @param session
     * @param timeout
     *          連接超時時間
     * @param sleepTimeout
     *          線程等待時間
     * @return
     * @throws Exception
     */
    public static String execShellCmd(String[] cmds,Session session,int timeout,int sleepTimeout) throws Exception {
        //打開通道
        ChannelShell channelShell = openChannelShell(session);
        //設置輸入輸出流
        PipedOutputStream pipedOut = new PipedOutputStream();
        ByteArrayOutputStream errorOut = new ByteArrayOutputStream();
        channelShell.setInputStream(new PipedInputStream(pipedOut));
        channelShell.setOutputStream(errorOut);
        channelShell.connect(timeout);
        for (String cmd : cmds){
            pipedOut.write(cmd.getBytes("UTF-8"));
            //線程休眠,保證執行命令后能夠及時返回響應數據
            Thread.sleep(sleepTimeout);

        }
        String msg = new String(errorOut.toByteArray(),"UTF-8");
        log.info(msg);
        pipedOut.close();
        errorOut.close();
        //關閉通道
        closeChannelShell(channelShell);
        return msg;
    }

    /**
     * 創建定時器,清除timeout 的 session 連接
     */
    public static void createSessionMonitor(){
        if (sessionMonitor == null){
            synchronized (SessionMonitor.class){
                if (sessionMonitor == null){
                    //定時器,定時清除失效的session
                    sessionMonitor = new SessionMonitor();
                    sessionMonitor.start();
                }
            }
        }
    }
    /**
     * 監控文件傳輸
     */
   static class FileSftpProgressMonitor extends TimerTask implements SftpProgressMonitor{

        private long progressInterval = 5 * 1000; // 默認間隔時候為5秒

        private boolean isEnd = false; // 記錄傳輸是否停止

        private long transfered; // 記錄已傳輸的數據總大小

        private long fileSize; // 記錄文件總大小

        private Timer timer; // 定時器對象

        private boolean isScheduled = false; // 記錄是否已啟動timer定時器

       private NumberFormat df = NumberFormat.getInstance(); //格式化

        public FileSftpProgressMonitor(long fileSize){
            this.fileSize = fileSize;
        }

        @Override
        public void run() {
            if (!isEnd()){
                long transfered = getTransfered();
                if (transfered != fileSize){
                    log.info("Current transfered: " + transfered + " bytes");
                    sendProgressMessage(transfered);
                }else{
                    log.info("transfered end.");
                    setIsEnd(true);
                }
            }else {
                log.info("Transfering done. Cancel timer.");
                stop(); // 若是傳輸停止,停止timer記時器
            }
        }

        /**
         * 定時器關閉
         */
        public void stop() {
            log.info("Try to stop progress monitor.");
            if (timer != null) {
                timer.cancel();
                timer.purge();
                timer = null;
                isScheduled = false;
            }
            log.info("Progress monitor stoped.");
        }

        /**
         * 定時器啟動
         */
        public void start() {
            log.info("Try to start progress monitor.");
            if (timer == null) {
                timer = new Timer();
            }
            timer.schedule(this, 1000, progressInterval);
            isScheduled = true;
            log.info("Progress monitor started.");
        }

        /**
         * 傳輸進度
         * @param transfered
         */
        private void sendProgressMessage(long transfered) {
            if (fileSize != 0) {
                double d = ((double)transfered * 100)/(double)fileSize;
                log.info("Sending progress message: " + df.format(d) + "%");
            } else {
                log.info("Sending progress message: " + transfered);
            }
        }

        @Override
        public void init(int i, String s, String s1, long l) {
            log.info("transfering start.");
        }

        @Override
        public boolean count(long l) {
            if (isEnd()){
                return false;
            }
            if (!getIsScheduled()){
                start();
            }
            add(l);
            return true;
        }
        @Override
        public void end() {
            setIsEnd(false);
            log.info("transfering end.");
        }


        private synchronized void add(long count) {
            transfered = transfered + count;
        }

        public synchronized  boolean isEnd() {
            return isEnd;
        }

        public synchronized  void setIsEnd(boolean isEnd) {
            this.isEnd = isEnd;
        }

        public synchronized  long getTransfered() {
            return transfered;
        }

        public synchronized  void setTransfered(long transfered) {
            this.transfered = transfered;
        }


        public synchronized  boolean getIsScheduled() {
            return isScheduled;
        }

        public synchronized  void setIsScheduled(boolean isScheduled) {
            this.isScheduled = isScheduled;
        }


    }

    /**
     * 定時器,定時清除失效的session
     */
    static class SessionMonitor extends TimerTask{

        private Timer timer; // 定時器對象
        private long progressInterval = 30 * 1000; // 默認間隔時候為30秒

        @Override
        public void run() {
            if (!cache.isEmpty()){
                Iterator iterator = cache.keySet().iterator();
                while (iterator.hasNext()){
                    String key = (String)iterator.next();
                    //清除失效session
                    if (testSessionIsDown(key)){
                        closeLongSessionByKey(key);
                    }
                }
            }
        }

        public void start(){
            if (timer == null){
                timer = new Timer();
            }
            timer.schedule(this,1000,progressInterval);
        }

        public void stop(){
            if (timer != null) {
                timer.cancel();
                timer.purge();
                timer = null;
            }
        }
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM