I created an object called Obj which sends messages over a Secure Shell channel. I can send characters in UTF-8, which means that the output stream must handle multi-byte characters. That is why I decided to use a buffered output stream writer. That is not relevant, so the code only references that part of the code with a comment.
I'd like the input stream to also handle multibyte characters. I know that the read() function of the InputStreamReader will return integers that correspond to UTF-16 code points or -1. My current implementation loops and tests for -1. It loops endlessly. Why?
Code
Here is my source code
public class Obj {
public String sendMessage(char[] message) {
final int CONNECTION_TIMEOUT_MILLISECONDS = 300;
final int IN_BUFFER_SIZE = 2048;
int codePoint;
StringBuilder sbResponse = new StringBuilder();
try {
ChannelShell channel = SshChannelFactory.getChannel(this);
if (channel == null) {
System.out.println("Unable to acquire channel for object \"{}\"", this);
throw new RuntimeException();
}
channel.connect(CONNECTION_TIMEOUT_MILLISECONDS);
System.out.println("Successfully opened channel to \"{}\"", channel.getHost());
}
/**
* Write some stuff in this try block.
*/
//try {
//} catch
/**
* Read the response in this try block.
*/
char[] buffer = new char[IN_BUFFER_SIZE];
int bytesReadOffset = 0;
try {
BufferedReader fromServerStream = new BufferedReader(new InputStreamReader(channel.getInputStream(), Charset.forName("UTF-8")), IN_BUFFER_SIZE);
while ((codePoint = fromServerStream.read()) != -1) {
sbResponse.append((char) codePoint);
} catch (IOException e) {
e.printStackTrace();
}
return sbResponse.toString();
}
public class SshChannelFactory {
public static ChannelShell getChannel(Obj obj) {
return createSshChannel(obj);
}
private static Session createSshSession(Obj obj) {
final JSch jsch = new JSch();
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
try {
Session session = jsch.getSession(obj.getUser(), obj.getHost(), obj.getPort());
session.connect();
return session;
} catch (JschException e) {
e.printStackTrace();
throw new RuntimeException();
}
}
private static ChannelShell createSshChannel() {
Session session = SSHSessionFactory.createSshSession(Obj obj)
try {
ChannelShell channel = (ChannelShell) session.openChannel("shell");
channel.setPty(true);
channel.setInputStream(null);
channel.setOutputStream(null);
return channel;
} catch (JSchException e) {
e.printStackTrace();
throw new RuntimeException();
}
}
}
The "shell" channel opens a shell.
We do not know what your code actually does. But I'd assume that you send some command to the shell to be executed and then you try to read the command output. And you probably expect to get -1 once the command output ends. You won't.
The shell output stream ends, only when the shell ends. And for that you need to send some command like exit
.
In general, you should not use the "shell" channel. It's intended for implementing an interactive shell session (like if you are implementing your own SSH terminal). That's something you rarely do.
To automate a command execution, use the "exec" channel.
See also What is the difference between the 'shell' channel and the 'exec' channel in JSch.
来源:https://stackoverflow.com/questions/56737291/why-does-reading-from-a-shell-channel-output-in-jsch-never-end-with-1