JSch ChannelExec加速

时间:2015-07-28 03:49:01

标签: ssh putty jsch

我正在编写一个与Linux服务器通信的JUnit集成测试。我正在使用JSch库来执行SSH和SFTP。我注意到使用PuTTY,最初使用SSH连接到服务器需要大约20 - 25秒,但是一旦我进入,shell命令在输入时非常快。但是,当我使用channelExec引用来执行系统命令时,对于每个执行的命令,它需要相同的20 - 25秒。我希望这些命令能够像在PuTTY中输入它们一样快。我注意到程序在从通道读取输入时挂起。在这里执行测试之前初始化JSch会话......

    public void connectToServer() {
    try {
        JSch jsch = new JSch();
        session = jsch.getSession(sUserName, sHostName, 22);
        session.setPassword(sPassword);
        session.setConfig("StrictHostKeyChecking", "no");
        if (DEBUG_MODE)
            println("UpdateProgram: Establishing SSH Connection...");
        session.connect();
        if (DEBUG_MODE)
            println("UpdateProgram: SSH Connection established.");
        if (DEBUG_MODE) println("UpdateProgram: Creating SFTP Channel.");
        sftpChannel = (ChannelSftp) session.openChannel("sftp");
        sftpChannel.connect();
        if (DEBUG_MODE) println("UpdateProgram: SFTP Channel created.");
    }
    catch (Exception e) {
        e.printStackTrace();
        System.exit(0);
    }
}

会话在所有测试完成后关闭......

public void exit() {
    // Close SFTP Channel
    if(sftpChannel != null) {
        sftpChannel.disconnect();
        if (DEBUG_MODE) println("UpdateProgram: SFTP Channel closed.");
    }
    else {
        if (DEBUG_MODE)
            println("UpdateProgram: No SFTP Channel to close.");            
    }

    // Close SSH resources
    if (session != null) {
        session.disconnect();
        if (DEBUG_MODE) println("UpdateProgram: SSH Disconnected.");
    }
    else {
        if (DEBUG_MODE)
            println("UpdateProgram: No SSH Connection to close.");
    }

    // Close DB2 database resources
    if (conn != null) {
        try {
            conn.close();
            if (DEBUG_MODE) println(
                    "UpdateProgram: Connection to DB2 database closed.");
        }
        catch (Exception e) {
            e.printStackTrace();
            System.exit(0);
        }
    }
    else {
        if (DEBUG_MODE)
            println("UpdateProgram: No DB2 database connection to close.");
    }
}

这是我的测试,它调用处理ChannelExec实例的runCProgram()方法......

public void effDateBeforeYesterday() {  
    String effDate = null,
           testRec = null;

    // Set effective date
    if(dateSize == 6)
        effDate = "000000";
    else 
        effDate = "00000000";

    // Upload Base test case and run C program
    program.setTransCount(5);
    program.put();
    program.runCProgram();

    // Upload test record   
    testRec = effDisDateInsert(effDate, currDate, true) + "\n";
    IO.fileWrite(testRec, file);
    program.setTransCount(1);
    program.put();
    program.runCProgram();

    // Query database for results

    // Clear table for next test

    assertTrue(true);
}

runCProgram()方法:

    public void runCProgram() {
    String command = "cd " + updateProgramPath + " && " + "./" + updateProgram
            + " -tc -b. -ppackage -r20150601000000 -n" + transCount + " -d"
            + dbName + " -u" + dbUserName + " -w" + dbPassword + " -s"
            + scheduleName;
    ChannelExec channel = null;
    InputStream in = null;

    try {
        // Setup channel for system command execution
        channel = (ChannelExec) session.openChannel("exec");
        if (DEBUG_MODE) println("UpdateProgram: Exec channel created.");
        channel.setCommand(command);
        if (DEBUG_MODE)
            println("UpdateProgram: Linux Command set to: " + command);
        channel.setInputStream(null);
        channel.setErrStream(System.err);
        in = channel.getInputStream();

        channel.connect();

        // Used for error detection in C program
        int temp = 0;

        if (DEBUG_MODE) println("UpdateProgram: Linux output: ");
        byte[] tmp = new byte[1024];
        while (true) {
            while (in.available() > 0) {
                int i = in.read(tmp, 0, 1024);
                if (i < 0) break;
                System.out.print(new String(tmp, 0, i));
            }
            if (channel.isClosed()) {
                if (in.available() > 0) continue;
                temp = channel.getExitStatus();
                if (temp != 0) throw new Exception(
                        "C Program Error, exit status " + temp);
                System.out.println("UpdateProgram: exit-status: " + temp);
                break;
            }
            try {
                Thread.sleep(1000);
            }
            catch (Exception ee) {}
        }

        channel.disconnect();
        if (DEBUG_MODE) println("UpdateProgram: Exec channel closed.");
    }

似乎为每个命令建立了一个新连接。有没有办法加快ChannelExec参考,以便它可以快速执行系统命令?任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:0)

好吧,所以我找到了解决问题的方法。我使用shell通道而不是exec,这样我就可以在程序中随时执行命令。这是我启动shell的代码......

// Global variables
PrintStream shellInput;
PipedInputStream pin2;

private void connectShell() {
    PipedInputStream pin = null;
    PipedOutputStream pout = null;
    PipedOutputStream pout2 = null;
    String tmpStr = null;
    byte[] tmp = null;

    try {
        // Setup for channel I/O
        pin = new PipedInputStream();
        pout = new PipedOutputStream(pin);
        pout2 = new PipedOutputStream();
        pin2 = new PipedInputStream(pout2);
        shellInput = new PrintStream(pout);

        // Create channel
        shellChannel = session.openChannel("shell");
        shellChannel.setInputStream(pin);
        shellChannel.setOutputStream(pout2);
        if (DEBUG_MODE)
            println("UpdateProgram: Connecting to remote shell...");
        shellChannel.connect();

        // Block until shell is connected
        tmpStr = "";
        tmp = new byte[1024];
        while (!tmpStr.contains("Username String")) {
            while (pin2.available() > 0) {
                int i = pin2.read(tmp, 0, 1024);
                tmpStr = new String(tmp, 0, i);
                if (i < 0) break;
                print(tmpStr);
            }
            Thread.sleep(1000);
        }

        if (DEBUG_MODE)
            println("UpdateProgram: Connected to remote shell.");
    }
    catch (Exception e) {
        e.printStackTrace();
        System.exit(0);
    }
}

我使用shellInput将命令发送到shell,使用pin2读取shell的输出。感谢Martin Prikryl的帮助!