【问题标题】:JSch ChannelExec SpeedupJSch ChannelExec 加速
【发布时间】:2015-10-18 11:05:22
【问题描述】:

我正在编写一个与 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 引用,以便它可以快速执行系统命令?任何帮助将不胜感激!

【问题讨论】:

  • 您的代码只执行一个命令。如果我们不知道您如何执行其他命令,我们该如何帮助您?
  • 抱歉代码示例不好。这是我的实际代码。
  • 我们仍然无法看到您创建session 的方式和时间。
  • 再次抱歉没有提供足够的信息。如果这还不够,请告诉我。
  • 好。谢谢。您的代码看起来正确。你能给我们看一下 PuTTY 的事件日志吗? (右键单击它的窗口标题并选择事件日志

标签: ssh putty jsch


【解决方案1】:

好的,所以我找到了解决问题的方法。我使用 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 的帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-02
    • 2011-09-07
    • 2018-06-19
    • 2015-04-12
    • 1970-01-01
    • 2021-04-17
    相关资源
    最近更新 更多