说明:需要只获得第一级文件夹目录
packagecom.sunsheen.jfids.studio.monitor.utils; importjava.io.BufferedReader; importjava.io.IOException; importjava.io.InputStream; importjava.io.InputStreamReader; importjava.io.PrintWriter; importjava.util.ArrayList; importjava.util.List; importorg.eclipse.core.runtime.Assert; importch.ethz.ssh2.ChannelCondition; importch.ethz.ssh2.Connection; importch.ethz.ssh2.StreamGobbler; /*** 遍历出远程服务器上指定目录下的所有文件夹 * * @authorWangSong * */ public classGetAllSubfolders { privateGetAllSubfolders(){} /*** 得到服务器上指定文件夹下所有子文件夹(第一级子文件夹) * @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 = newStreamGobbler(sess.getStdout()); InputStream stderr = newStreamGobbler(sess.getStderr()); BufferedReader stdoutReader = new BufferedReader(newInputStreamReader(stdout)); BufferedReader stderrReader = new BufferedReader(newInputStreamReader(stderr)); //向服务器上输入命令 PrintWriter out = newPrintWriter(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); } returnfolderNameList; } }
上面代码可能会出现线程阻塞(客户端等待服务器应答信息),参考下面方式解决
使用ch.ethz.ssh2中sess.execCommand方法导致线程卡死的原因分析
背景
前几天有同事反馈,说生产上的定时任务好像卡住了,没有执行。
上服务器,查看应用日志,定时任务确实没有执行。
分析
这种情况,第一时间先把线程dump文件导出来
分析dump文件,发现线程一直在执行sess.execCommand方法
线程现在一直在c.wait这里,等待服务器返回信息将他唤醒。
问题是服务器不知道啥情况,就是不返回,所以线程就一直卡在这里了
解决方案
一般来说可以通过设置超时时间来处理这些问题。但是这个方法根本没有超时时间设置的参数。
好在找到了waitForCondition这个方法,可以设置一些条件来达到超时时间设置的效果.
/**列出目录下的文件信息 */ public staticString[] getRemoteDirFileNames(Connection conn, String remoteDir){ Session sess=null; try{ sess =conn.openSession(); sess.execCommand("ls -lt "+remoteDir); InputStream stdout = newStreamGobbler(sess.getStdout()); InputStream stderr = newStreamGobbler(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(" "); } } 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; }