說明:須要只得到第一級文件夾目錄 java
package com.sunsheen.jfids.studio.monitor.utils; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import org.eclipse.core.runtime.Assert; import ch.ethz.ssh2.ChannelCondition; import ch.ethz.ssh2.Connection; import ch.ethz.ssh2.StreamGobbler; /** * 遍歷出遠程服務器上指定目錄下的全部文件夾 * * @author WangSong * */ public class GetAllSubfolders { private GetAllSubfolders(){} /** * 獲得服務器上指定文件夾下全部子文件夾(第一級子文件夾) * @return */ public static List<Object> getSubfolderName(String romoteAddr,String username, String password,String targetFolder) { List<Object> folderNameList = new ArrayList<Object>(); try { Connection connection = new Connection(romoteAddr);// 建立一個鏈接實例 connection.connect();// Now connect boolean isAuthenticated = connection.authenticateWithPassword(username, password);//認證 Assert.isTrue(isAuthenticated, "用戶名或密碼錯誤!"); ch.ethz.ssh2.Session sess = connection.openSession();// 創建一個會話 sess.requestPTY("bash"); sess.startShell(); InputStream stdout = new StreamGobbler(sess.getStdout()); InputStream stderr = new StreamGobbler(sess.getStderr()); BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(stdout)); BufferedReader stderrReader = new BufferedReader(new InputStreamReader(stderr)); //向服務器上輸入命令 PrintWriter out = new PrintWriter(sess.getStdin()); out.println("cd " + targetFolder);//進入日誌文件存放的目錄 out.println("ls -ld */"); out.println("exit"); out.close(); sess.waitForCondition(ChannelCondition.CLOSED|ChannelCondition.EOF | ChannelCondition.EXIT_STATUS,30000); //本機查看遠程操做的指令及狀態 System.out.println("輸入指令後對應的顯示信息:"); while (true) { String line = stdoutReader.readLine(); if (line == null) break; System.out.println(line); //取出文件夾那條記錄 if(line.contains("drwxr-xr-x")){ //取出正確的文件夾名 StringBuffer sb = new StringBuffer(line.substring(line.lastIndexOf(" "),line.lastIndexOf("/"))); line = sb.toString().replace(" ", ""); folderNameList.add(line); } } System.out.println("ExitCode: " + sess.getExitStatus()); //關閉鏈接 sess.close(); connection.close(); stderrReader.close(); stdoutReader.close(); } catch (IOException e) { e.printStackTrace(System.err); System.exit(2); } return folderNameList; } }
上面代碼可能會出現線程阻塞(客戶端等待服務器應答信息),參考下面方式解決bash
技術標籤: ssh2 sess.execCommand 線程卡死服務器
前幾天有同事反饋,說生產上的定時任務好像卡住了,沒有執行。
上服務器,查看應用日誌,定時任務確實沒有執行。markdown
這種狀況,第一時間先把線程dump文件導出來
分析dump文件,發現線程一直在執行sess.execCommand方法eclipse
線程如今一直在c.wait這裏,等待服務器返回信息將他喚醒。
問題是服務器不知道啥狀況,就是不返回,因此線程就一直卡在這裏了ssh
通常來講能夠經過設置超時時間來處理這些問題。可是這個方法根本沒有超時時間設置的參數。
好在找到了waitForCondition這個方法,能夠設置一些條件來達到超時時間設置的效果.atom
/* *列出目錄下的文件信息 */ public static String[] getRemoteDirFileNames(Connection conn, String remoteDir){ Session sess=null; try { sess = conn.openSession(); sess.execCommand("ls -lt "+remoteDir); InputStream stdout = new StreamGobbler(sess.getStdout()); InputStream stderr = new StreamGobbler(sess.getStderr()); byte[] buffer = new byte[100]; String result = ""; while (true) { if ((stdout.available() == 0)) { int conditions = sess.waitForCondition(ChannelCondition.STDOUT_DATA | ChannelCondition.STDERR_DATA | ChannelCondition.EOF, 1000*5); if ((conditions & ChannelCondition.TIMEOUT) != 0) { break;//超時後退出循環,要保證超時時間內,腳本能夠運行完成 } if ((conditions & ChannelCondition.EOF) != 0) { if ((conditions & (ChannelCondition.STDOUT_DATA | ChannelCondition.STDERR_DATA)) == 0) { break; } } } if(stdout!=null){ String fileNames= ConvertUtil.parse_String(stdout); if(fileNames!=null){ return fileNames.split("\n"); } } while (stderr.available() > 0) { int len = stderr.read(buffer); if (len > 0){ result += new String(buffer, 0, len); } } } } catch (Exception e) { log.info("獲取指定目錄下文件列表失敗:"+e.getMessage()); }finally { sess.close(); } return null; }