Хорошо, у меня проблема, когда ответ от оболочки очень противоречивый.Приветственное сообщение, например, может прийти в 2 отдельных ответаИ по какой-то причине, когда я использую какую-либо команду после этого, приглашение будет дважды отображаться в моем ответе.
Я заметил, что эти проблемы возникают только при использовании моих собственных потоковых потоков ввода / вывода.Когда я использую System.in
и System.out
, эти проблемы вообще не возникают.
Вот изображение, где я использую System.in
и System.out
: ![Used commands:](https://i.stack.imgur.com/eEqLU.png)
При использовании моих собственных потоков ввода / вывода: ![Used commands:](https://i.stack.imgur.com/cNXpl.png)
Ниже приведен соответствующий код.
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
Я попытался увеличить размер своих входных потоков, ноэто не сработало.
Эта проблема действительно расстраивает меня.Если кто-нибудь знает, как я могу решить мою проблему, я буду очень признателен за это.
Примечание: я также заметил, что при использовании моих потоковых каналов это происходит довольно медленно.Как я могу ускорить это?