Получение командной строки дважды в Java JSch Shell - PullRequest
0 голосов
/ 22 сентября 2018

Хорошо, у меня проблема, когда ответ от оболочки очень противоречивый.Приветственное сообщение, например, может прийти в 2 отдельных ответаИ по какой-то причине, когда я использую какую-либо команду после этого, приглашение будет дважды отображаться в моем ответе.

Я заметил, что эти проблемы возникают только при использовании моих собственных потоковых потоков ввода / вывода.Когда я использую System.in и System.out, эти проблемы вообще не возникают.

Вот изображение, где я использую System.in и System.out: Used commands:

При использовании моих собственных потоков ввода / вывода: Used commands:

Ниже приведен соответствующий код.

SSHConnection.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

Я попытался увеличить размер своих входных потоков, ноэто не сработало.

Эта проблема действительно расстраивает меня.Если кто-нибудь знает, как я могу решить мою проблему, я буду очень признателен за это.

Примечание: я также заметил, что при использовании моих потоковых каналов это происходит довольно медленно.Как я могу ускорить это?

1 Ответ

0 голосов
/ 22 сентября 2018

Правильно ли вы обрабатываете CR (возврат каретки) ?

Сервер, вероятно, отправляет запрос дважды во всех случаях.Но если между двумя приглашениями есть CR, при печати на System.out второе приглашение перезапишет первое.Если ваш поток интерпретирует CR как «новую строку» (= перевод строки) , вы получите два запроса.

...