1. 程式人生 > >使用ganyssh包進行linux連線時讀回顯時readLine發生io阻塞解決方法

使用ganyssh包進行linux連線時讀回顯時readLine發生io阻塞解決方法

原因分析,Ganymed SSH-2這個包感覺不是很好用,比如我根據連線建立一個session的時候,在呼叫exeCommand方法的時候只能用一次,如果想繼續用需要關閉session在一次重新開啟,所以我本地就寫了一個新的命令執行方法,直接獲取輸出流然後以位元組碼的形式flush出去,
public void sendCommand(String cmd) {

    try {
        this.dos.write(cmd.getBytes());
        this.dos.write("\r".getBytes());
        this.dos.flush();
        try {
            // 每次睡眠一下等待程式相應。
            Thread.sleep(400);
        } catch (InterruptedException ex1) {
        }
    } catch (IOException ex) {
    }

}

這樣就可以在一個session中執行多個命令了

在讀取回顯資訊的時候使用的是BufferReader類的readLine方法,但是在讀取最後的回顯時發生了阻塞,程式開在這裡,這個原因是,readLine方法在讀取資料的時候要識別到\n 或者\r,如果返回的回顯中不存在,則會繼續等待資料,導致當前的程式無法進行下去,目前針對這個問題有多種解決的方法,包括讀取位元組碼,然後自己在編碼,或者只讀取字元,使用read方法,但是這些方法都不好,會涉及很多的編碼問題,啊,字串的擷取問題,緩衝區大小,如何動態計算,只能參照java中的readLine去寫,但是都不好,通過查詢資料終於找到了解決辦法就是開啟新的執行緒去執行回顯,這樣就不會影響當前執行緒,我程式中用的是執行緒池,因為執行緒池方便簡單,功能強大,弊端少,最主要我不想寫太多的執行緒程式碼,開啟新的執行緒去執行回顯程式碼後,主程式的依舊會繼續執行,最後只要我們關閉流,使用的執行緒自然會被釋放,所以這是一個很好的方法,建議大家使用,說真的 這個包太尼瑪的坑了。
程式碼如下
package com.ultrapower.Ty.test;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.junit.Test;
import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.Session;
import ch.ethz.ssh2.StreamGobbler;

public class testJframe3 {
private Session session = null;
private BufferedReader br = null;
private Connection conn = null;
private String hostname = “10.102.45.16”;
private static String username = “tyroot”;
private static String password = “Yhblsqt!#m3”;
public BufferedReader dis = null;
public DataOutputStream dos = null;
// 初始化buffer
private ExecutorService service = Executors.newFixedThreadPool(3);

@Test
public void testSsh() {
    try {
        auth();
        sendCommand("ls");
        execCommand();
        sendCommand("cd /opt");
        sendCommand("ls");
        execCommand();
        System.out.println("ExitCode: " + session.getExitStatus());
        /* Close this session */
        closeAll();
    } catch (IOException e) {
        e.printStackTrace(System.err);
        System.exit(2);
    }
}
/**
 * 讀取回顯
 * @throws IOException
 */
public void execCommand() throws IOException {
    service.submit(new Runnable() {
        // BufferedReader stdout1 = new BufferedReader(new InputStreamReader(new
        @Override
        public void run() {
            String line;
            try {
                while ((line = dis.readLine()) != null) {
                    System.out.println(line);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    });
}
/**
 * 傳送命令。
 * @param cmd
 */
public void sendCommand(String cmd) {

    try {
        this.dos.write(cmd.getBytes());
        this.dos.write("\r".getBytes());
        this.dos.flush();
        try {
            // 每次睡眠一下等待程式相應。
            Thread.sleep(400);
        } catch (InterruptedException ex1) {
        }
    } catch (IOException ex) {
    }

}
/**
 * 
 * @throws IOException
 */
public void auth() throws IOException {
    conn = new Connection(hostname, 22);// 首先構造一個聯結器,傳入一個需要登陸的ip地址
    /* Now connect */
    conn.connect();
    System.out.println("connect ok");

    /*
     * Authenticate. If you get an IOException saying something like
     * "Authentication method password not supported by the server at this stage."
     * then please check the FAQ.
     */
    // 模擬登陸目的伺服器 傳入使用者名稱和密碼 ,
    // 它會返回一個布林值,true 代表成功登陸目的伺服器,否則登陸失敗
    boolean isAuthenticated = conn.authenticateWithPassword(username, password);
    if (isAuthenticated == false)
        throw new IOException("Authentication failed.");
    this.session = this.conn.openSession();
    this.session.requestPTY("vt100", 80, 800, 0, 0, null);
    this.session.startShell();
    this.dis = new BufferedReader(new InputStreamReader(new StreamGobbler(session.getStdout()), StandardCharsets.UTF_8));
    this.dos = new DataOutputStream(this.session.getStdin());
    System.out.println("Authentication ok");
    /* Create a session */

    System.out.println("Here is some information about the remote host:");
}

public void closeAll() throws IOException {
    if (this.session != null) {
        session.close();
    }
    if (this.conn != null) {
        conn.close();
    }
    if (this.br != null) {
        this.br.close();
    }

}

}這裡寫程式碼片