繁体   English   中英

在 Java JSch Shell 中两次获得 shell 提示

[英]Getting shell prompt twice in Java JSch Shell

好的,我遇到了一个问题,shell 的响应非常不一致。 例如,欢迎消息可以有 2 个单独的响应。 出于某种原因,当我在此之后使用任何命令时,提示将在我的响应中出现两次。

我注意到只有在使用我自己的管道输入/输出流时才会出现这些问题。 当我使用System.inSystem.out ,这些问题根本不会发生。

这是我使用System.inSystem.out的图片: 使用的命令:“cd ../”、“ls”、“cd lib”

使用我自己的管道输入/输出流时: 使用的命令:“cd ../”、“ls”、“cd lib”

下面是相关代码。

SSH连接.java

package com.displee.ssh;

import com.jcraft.jsch.*;

import java.util.function.Function;

public class SSHConnection {

    private static final JSch JSCH_INSTANCE = new JSch();

    private Session session;

    private ShellSession shellSession;

    public SSHConnection(String ip, String username, String password) {
        try {
            this.session = JSCH_INSTANCE.getSession(username, ip);
            this.session.setPassword(password);
            this.session.setConfig("StrictHostKeyChecking", "no");
        } catch(Exception e) {
            e.printStackTrace();
            this.session = null;
        }
    }

    public boolean connect() {
        try {
            session.connect();
            return true;
        } catch(Exception e) {
            e.printStackTrace();
            session.disconnect();
            return false;
        }
    }

    public boolean isConnected() {
        return session.isConnected();
    }

    public void disconnect() {
        session.disconnect();
    }

    public boolean startShellSession(Function<String, Void> callback) {
        try {
            shellSession = new ShellSession();
            shellSession.start(session, callback);
            return true;
        } catch(Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public void writeShellMessage(String message) {
        shellSession.write(message + "\r\n");
    }

}

ShellSession.java

package com.displee.ssh;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelShell;
import com.jcraft.jsch.Session;

import java.io.*;
import java.util.function.Function;

/**
 * A class representing a shell session.
 * @author Displee
 */
public class ShellSession {

    /**
     * If this session is running.
     */
    private boolean running = true;

    private PipedOutputStream poutWrapper;

    private PipedInputStream pin = new PipedInputStream(4096);

    private PipedInputStream pinWrapper = new PipedInputStream(4096);

    private PipedOutputStream pout;

    private String lastCommand;

    /**
     * Constructs a new {@code ShellSession} {@code Object}.
     */
    public ShellSession() {
        try {
            pout = new PipedOutputStream(pinWrapper);
            poutWrapper = new PipedOutputStream(pin);
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Start this shell session.
     * @param session The ssh session.
     */
    public void start(Session session, Function<String, Void> callback) {
        ChannelShell shellChannel = null;
        try {
            shellChannel = (ChannelShell) session.openChannel("shell");
            shellChannel.setInputStream(pin);
            shellChannel.setOutputStream(pout);
            shellChannel.connect();
        } catch(Exception e) {
            e.printStackTrace();
        }
        if (shellChannel == null) {
            return;
        }
        final Channel channel = shellChannel;
        Thread thread = new Thread(() -> {
            while (running) {
                try {
                    if (pinWrapper.available() != 0) {
                        String response = readResponse();
                        callback.apply(response);
                    }
                    Thread.sleep(100);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            channel.disconnect();
        });
        thread.setDaemon(true);
        thread.start();
    }

    /**
     * Stop this shell session.
     */
    public void stop() {
        running = false;
    }

    /**
     * Send a message to the shell.
     * @param message The message to send.
     */
    public void write(String message) {
        lastCommand = message;
        try {
            poutWrapper.write(message.getBytes());
        } catch(IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Read the response from {@code pinWrapper}.
     * @return The string.
     * @throws IOException If it could not read the piped stream.
     */
    private synchronized String readResponse() throws IOException {
        final StringBuilder s = new StringBuilder();
        while(pinWrapper.available() > 0) {
            s.append((char) pinWrapper.read());
        }
        return s.toString();
    }

}

我的 JavaFX 控制器:

package com.displee.ui;

import com.displee.ssh.SSHConnection;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;

import java.net.URL;
import java.util.ResourceBundle;

public class Controller implements Initializable {

    @FXML
    private TextArea console;

    @FXML
    private TextField commandInput;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        SSHConnection connection = new SSHConnection("host", "username", "password");
        connection.connect();
        connection.startShellSession(s -> {
            console.appendText(s);
            return null;
        });
        commandInput.setOnAction(x -> {
            connection.writeShellMessage(commandInput.getText());
            commandInput.clear();
        });
    }

}

完整代码: https : //displee.com/upload/SSHProject.zip

我尝试增加输入流的大小,但这没有用。

这个问题真的让我很沮丧。 如果有人知道我如何解决我的问题,我将不胜感激。

注意:我还注意到使用我的管道流时它很慢。 我怎样才能加快速度?

您是否正确处理了CR(回车)

在所有情况下,服务器可能会发送两次提示。 但是,如果两个提示之间有 CR,则在System.out上打印时,第二个提示将覆盖第一个提示。 而如果您的流将 CR 解释为“换行”(=换行) ,您会收到两个提示。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM