我正在研究新项目。我试图通过以太网从Java发送命令到外部计算机(Linux)。我正在使用Jsch来创建shell连接。我将shell输入和输出设置为System.out和System.in。
((ChannelShell)channel).setInputStream(System.in);
((ChannelShell)channel).setOutputStream(System.out);
它适用于控制台!但我需要从javafx GUI应用程序远程访问它。我已经解决了将System.out重定向到TextArea的问题:
public void redirectOutputStream() {
OutputStream out = new OutputStream() {
private final StringBuilder sb = new StringBuilder();
@Override
public void write(int b) throws IOException {
if (b == '\r') {
return;
}
if (b == '\n') {
final String tmp = sb.toString() + "\n";
text.add(tmp);
updateText(text);
sb.setLength(0);
} else {
sb.append((char) b);
}
}
};
System.setOut(new PrintStream(out, true));
// System.setErr(new PrintStream(out, true));
}
但现在我还需要将System.in重定向到TextField,以便我可以在TextField中写入内容,按回车并通过shell将其发送到外部计算机。
任何帮助都会受到赞赏。谢谢!
修改 对不起,仍然不适合我:( ... 现在我有了这段代码(我使用的是javafx):
/** Tmp queue for standard input redirecting */
BlockingQueue<Integer> stdInQueue = new LinkedBlockingQueue<>();
@Override
public void initialize(URL arg0, ResourceBundle arg1) {
redirectOutputStream();
redirectInputStream();
}
/** redirects standard System.out to GUI command_window */
public void redirectOutputStream() {
OutputStream out = new OutputStream() {
private final StringBuilder sb = new StringBuilder();
@Override
public void write(int b) throws IOException {
if (b == '\r') {
return;
}
if (b == '\n') {
final String tmp = sb.toString() + "\n";
text.add(tmp);
updateText(text);
sb.setLength(0);
} else {
sb.append((char) b);
}
}
};
System.setOut(new PrintStream(out, true));
System.setErr(new PrintStream(out, true));
}
/** redirects standard System.in to GUI command_line */
public void redirectInputStream() {
InputStream in = new InputStream() {
@Override
public int read() throws IOException {
try {
int c = stdInQueue.take().intValue();
return c;
} catch (InterruptedException exc) {
Thread.currentThread().interrupt();
return -1;
}
}
};
System.setIn(in);
}
@FXML
void sendButtonPressed(ActionEvent event) {
if (!command_line.getText().isEmpty()) {
for (char c : command_line.getText().toCharArray()) {
System.out.write(new Integer(c)); //display in ListView (output)
stdInQueue.add(new Integer(c));
}
System.out.write(new Integer('\n')); //display in ListView (output)
stdInQueue.add(new Integer('\n'));
command_line.clear();
}
}
System.out和System.err的重定向工作完美。它显示在javafx ListView中。
问题仍然是在ListView下我有一个“命令行”javafx TextField我需要在这个TextField中编写一些ssh命令,并在按下“enter”或点击“send”按钮时将其重定向到System.in
我需要这样做的原因是我正在使用为System.in和System.out设置的SSH通信。它完全适用于控制台(已测试),但不适用于我的GUI应用程序。
感谢您提供进一步的建议!
答案 0 :(得分:0)
您可以设置BlockingQueue<Integer>
发送单个字符,然后让输入流从中获取字符:
BlockingQueue<Integer> stdInQueue = new LinkedBlockingQueue<>();
System.setIn(new InputStream() {
@Override
public int read() throws IOException {
try {
int c = stdInQueue.take().intValue();
return c;
} catch (InterruptedException exc) {
Thread.currentThread().interrupt();
return -1 ;
}
}
});
textField.setOnAction(e -> {
for (char c : textField.getText().toCharArray()) {
stdInQueue.add(new Integer(c));
}
stdInQueue.add(new Integer('\n'));
textField.clear();
});
这是一个快速演示:对于测试我只是设置了一个从System.in
读取的后台线程:
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class StdInFromTextField extends Application {
@Override
public void start(Stage primaryStage) {
TextField textField = new TextField();
BlockingQueue<Integer> stdInQueue = new LinkedBlockingQueue<>();
System.setIn(new InputStream() {
@Override
public int read() throws IOException {
try {
int c = stdInQueue.take().intValue();
return c;
} catch (InterruptedException exc) {
Thread.currentThread().interrupt();
return -1 ;
}
}
});
textField.setOnAction(e -> {
for (char c : textField.getText().toCharArray()) {
stdInQueue.add(new Integer(c));
}
stdInQueue.add(new Integer('\n'));
textField.clear();
});
// for testing:
Thread readThread = new Thread(() -> {
try {
int i ;
while ((i = System.in.read()) != -1) {
System.out.print((char)i);
}
} catch (IOException exc) {
exc.printStackTrace();
}
});
readThread.setDaemon(true);
readThread.start();
primaryStage.setScene(new Scene(new StackPane(textField), 300, 120));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
答案 1 :(得分:0)
好的,我现在有工作代码。问题是,我没弄明白,如何重定向System.in(这可能是不可能的)。所以我不得不直接从SSH连接器重定向流。
以下是我在jsch流中设置输入和输出的方法:
public class ToradexSSHCommunicator {
String user;
String password;
String ip;
int port;
InputStream fromChannel;
OutputStream toChannel;
/** logger for error output feed */
private static final Logger LOGGER = Logger.getLogger(ToradexSSHCommunicator.class);
public ToradexSSHCommunicator(String user, String password, String ip, int port) {
this.user = user;
this.password = password;
this.ip = ip;
this.port = port;
}
public void startup() {
Session session = null;
ChannelShell channel = null;
boolean isConnected = false;
JSch jsch = new JSch();
while (!isConnected) {
try {
session = jsch.getSession(user, ip, port);
session.setPassword(password);
session.setConfig("StrictHostKeyChecking", "no");
LOGGER.info("Establishing Toradex Connection...");
session.setTimeout(1000);
session.connect();
LOGGER.info("Toradex connection established.");
LOGGER.info("Creating Toradex channel...");
channel = (ChannelShell) session.openChannel("shell");
LOGGER.info("Toradex channel created.");
fromChannel = channel.getInputStream();
toChannel = channel.getOutputStream();
channel.connect();
isConnected = true;
}
catch (JSchException e) {
LOGGER.error("Toradex connection error.....RECONNECTING", e);
session.disconnect();
}
catch (IOException e) {
LOGGER.error("Toradex connection error.....RECONNECTING", e);
session.disconnect();
}
}
}
public InputStream getFromChannel() {
return fromChannel;
}
public OutputStream getToChannel() {
return toChannel;
}
}
使用此流的GUI部分:
@FXML
private ListView<String> command_window_toradex;
@FXML
private TextField command_line;
private ToradexSSHCommunicator comm;
private BufferedReader br;
private BufferedWriter bw;
@FXML
void sendButtonPressed(ActionEvent event) {
executor.submit(new Task<Void>() {
@Override
protected Void call() throws Exception {
writeCommand();
return null;
}
});
}
/** initialize SSH connection to Toradex and redirect input and output streams to GUI */
private void initToradex() {
comm = new ToradexSSHCommunicator(GuiConstants.TORADEX_USER, GuiConstants.TORADEX_PASSWORD,
GuiConstants.TORADEX_IP_ADDRESS, GuiConstants.TORADEX_PORT);
comm.startup();
br = new BufferedReader(new InputStreamReader(comm.getFromChannel()));
bw = new BufferedWriter(new OutputStreamWriter(comm.getToChannel()));
}
private void writeCommand() throws IOException {
if (!command_line.getText().isEmpty()) {
String command = command_line.getText();
bw.write(command + '\n');
bw.flush();
command_line.clear();
}
}
private void readCommand() throws IOException {
String commandLine = null;
while (true) {
commandLine = br.readLine();
textToradex.add(commandLine);
}
}
有效!但是现在这是整个代码,如果您需要任何进一步的帮助,请问。