execute multiple command with jsch session and channelexec - java

I struggled to get this working but eventually got the script to execute a command (executing a sh script) on a remote unix server. I am trying to execute a second command and keep getting an error either with creating a new channel or using the same.
try {
((ChannelExec) channel).setCommand(command);
PrintStream out= new PrintStream(channel.getOutputStream());
InputStream in = channel.getInputStream();
channel.connect();
BufferedReader scriptReader= new BufferedReader(new InputStreamReader(in));
scriptOutput = scriptReader.readLine();
sb = new StringBuilder();
while ((scriptOutput = scriptReader.readLine())!= null) {
sb.append(scriptOutput + "\n");
This is the first snippet of the channel execute which works fine. Now the next method snippet is called immediately after consuming the above inputstream:
try {
StringBuilder sb = new StringBuilder();
command = new_command;
((ChannelExec) channel).setCommand(command);
InputStream in = channel.getInputStream();
channel.connect();
BufferedReader scriptReader= new BufferedReader(new InputStreamReader(in));
scriptOutput = scriptReader.readLine();
//StringBuilder sb = new StringBuilder();
for(int c=0; c < consumerList.size(); c++){
....
Now this returns the following error:
com.jcraft.jsch.JSchException: channel is not opened.
Now if I create a new channel with the same session I get a null response from returned stream. I did test the command in the remote shell and it works fine:
int counter = 0;
Channel channelII = session.openChannel("exec");
try {
StringBuilder sb = new StringBuilder();
command = new_command;
((ChannelExec) channelII).setCommand(command);
InputStream in = channelII.getInputStream();
channelII.connect();
BufferedReader scriptReader= new BufferedReader(
new InputStreamReader(in));
scriptOutput = scriptReader.readLine();
the second command is the following and I want to be able to repeatedly execute it for different consumer groups:
/usr/kafka/bin/kafka-consumer-groups.sh --bootstrap-server
192.xxx.xx.xxx:9092 --describe -group consumergroup1
EDIT:
response of second command:
TOPIC PARTITION CURRENT-OFFSET LOG-END-OFFSET
LAG CONSUMER-ID HOST
CLIENT-ID
output.influxDB 1 94919 2781796
2686877 - -
-
output.influxDB 0 94919 2781798
2686879 - -
-
output.influxDB 2 94918 2781795
2686877 - -
-

Thank you to Nicholas and Martin for their responses. I figured out what was wrong and wanted to post an answer as I do realize that little things like this do crop up for us 'dumb' programmers out there who ask ridiculous questions that incur negative votes. The output for the second command was returning a warning / error response in the first line and by not including the following I was not seeing that and reading the next line was empty. I know it's stupid and should have figured this out before posting because that is the point of this site: post questions that are beyond the knowledge of others. But since I should have innately known this:
Anyway ensure the following line is included:
((ChannelExec)channelII).setErrStream(System.err);
and also read the stream with a loop and not just test with reading the first line.
while ((scriptOutput = scriptReader.readLine())!= null) {
sb.append(scriptOutput + "\n");
}
I hope this can at least be a lesson to some if not a solution.

Related

JSch - How to capture stream from remote server using PortForwarding L?

I tried to use InputStream and Buffer[], also BufferedReader, also PipedInputStream. For all cases i got null:
sessionB = jSch.getSession(username, "localhost", forwardedPort);
sessionB.connect();
if(sessionB.isConnected()) {
System.out.println("Connected host B!");
channel = (ChannelExec) sessionB.openChannel("exec");
br = new BufferedReader(new
InputStreamReader(channel.getInputStream()));
((ChannelExec)channel).setCommand("command");
((ChannelExec)channel).setErrStream(System.err);
channel.connect();
if(channel.isConnected()) {
System.out.println("Channel is connected!");
}
String line;
while((line = br.readLine()) != null) {
System.out.println(line);
}
And console output:
Connected host A! Connected host B! Channel is connected!
Problem: I got nothing printed (System.out.println(line);)
There is a way to get that stream from exec channel over portforwarding ? Thanks for your help
get/setInputStream and get/setOutputStream only concern the standard input/output of the command, nothing to do with port forwarding.
The port forwarding is done through two functions setPortForwardingL and setPortForwardingR.
You should have something like that in your code.
int assinged_port=session.setPortForwardingL(lport, rhost, rport);
As always, there is very few documentation on JSCH but a lot of detailed examples for L forwarding and R forwarding
The port forwarding is done on the session so I'm not sure you also need an active connection. But if you do, you should consider opening a 'shell' connection instead of an 'exec'. Then you wouldn't have to run a useless command just to maintain the connection.
PS: Some code is missing so it's difficult to say something precise on the example given in the question.
Thanks for your help. I solved it using Pipes, i share what i did:
PipedInputStream en = new PipedInputStream();
pin = new PipedOutputStream((PipedInputStream) en);
BufferedReader br = new BufferedReader(new InputStreamReader((PipedInputStream)
channel.getInputStream()));
channel.connect(5*1000);
String received=null;
while((received=br.readLine())!=null) {
System.out.println(received);
}

Client's BufferedReader not recieving line from Server, using sockets (Java)

I'm trying to make a chat application between a server and clients which are seperate classes. I'm not copying the whole code, but this is the part I'm not sure is set up correctly:
Server:
ServerSocket s = null;
Socket c = null;
s = new ServerSocket(5002);
c = s.accept();
BufferedReader in = new BufferedReader(new InputStreamReader(c.getInputStream()))
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(c.getOutputStream()));
out.flush();
String line;
line = in.readLine();
out.write("#W|Welcome");
line = in.readLine();
out.write("#W|Welcome");
line = in.readLine();
out.write("#W|Welcome");
Client :
Socket socket = new Socket("localhost", 5002);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream ()));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
String line;
out.flush();
out.write("#J|test");
line = in.readLine();
out.write("#J|test");
line = in.readLine();
After the client does out.println(), the server's in.readLine() gets the line. But when it's the other way around, the client keeps waiting at in.readLine(). (I used the debugger and watched the server execute out.println() and go past it, while the client is still stuck at in.readLine().
Are my data streams set up correctly or is there probably an error in my code somewhere else? I'm not sure how to check in the debugger if the streams are connected correctly.
[Quoting my comment above:]
There is nothing here that [reads or] writes lines.
That remains true. All you have is:
out.write("#W|Welcome");
etc.
don't forget to call newLine() as necessary
You forgot.

Cannot read line break/carriage return from socket response

I am sending setup commands to a TP-LINK wireless router through a telnet connection:
Trying 1.2.3.4...
Connected to 1.2.3.4.
Escape character is '^]'.
*HELLO*$$$
CMD
factory RESET
factory RESET
Set Factory Defaults
<4.00> set sys autoconn 0
set sys autoconn 0
AOK
<4.00>
...
I have a PHP code that performs the sending of commands and gets the response using sockets:
socket_write($socket, "factory RESET\r"); // send command
$response = socket_read($socket, 256); // get response
PHP works fine. The $response variable contains:
factory RESET
Set Factory Defaults
But using the Java I have problems. Using a BufferedReader object to read response, I can get the first line content. but I can not get the following lines:
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// ...
bw.write("factory RESET");
bw.newLine();
bw.flush();
// ...
StringBuilder sb = new StringBuilder();
String s;
while ((s = br.readLine()) != null) {
sb.append(s);
}
I can get the first line content, but the second reading don't proceed and don't raise exception...
If I use the read function, only the first row is returned:
char[] buffer = new char[256];
br.read(buffer, 0, 256);
String response = new String(buffer); // response is "factory RESET"
What is the problem?
Your PHP code execute two reads. Your Java code attempts to read until end of stream, which only happens when the peer closes the connection. Do a single read.
The line separator in the Telnet protocol is defined as \r\n, unless you're using binary mode, which you aren't. Not as\r or whatever BufferedWriter may do on your platform.

pass enter key from Java to Shell script

I am trying a Java program to run multiple commands in unix environment. I would need to pass 'ENTER' after each command. Is there some way to pass enter in the InputStream.
JSch jsch=new JSch();
Session session=jsch.getSession("MYUSERNAME", "SERVER", 22);
session.setPassword("MYPASSWORD");
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
Channel channel= session.openChannel("shell");
channel.setInputStream(getInputStream("ls -l"));
channel.setInputStream(getInputStream("\r\n"));
channel.setInputStream(getInputStream("pwd"));
channel.setInputStream(getInputStream("\r\n"));
channel.connect();
When I do ls -l, I want to add enter here, so that the command is executed.
getInputStream is a method to convert String into InputStream.
Any help will be appreciated.
According to the JSch javadoc, you must call setInputStream() or getOutputStream() before connect(). You can only do one of these, once.
For your purposes, getOutputStream() seems more appropriate. Once you have an OutputStream, you can wrap it in a PrintWriter to make sending commands easier.
Similarly you can use channel.getInputStream() to acquire an InputStream from which you can read results.
OutputStream os = channel.getOutputStream();
PrintWriter writer = new PrintWriter(os);
InputStream is = channel.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
channel.connect();
writer.println("ls -l");
String response = reader.readLine();
while(response != null) {
// do something with response
response = reader.readLine();
}
writer.println("pwd");
If you're determined to use setInputStream() instead of getOutputStream() then you can only do that once, so you'll have to put all your lines into one String:
channel.setInputStream(getInputStream("ls -l\npwd\n"));
(I don't think you need \r, but add it back in if necessary)
If you're not familiar with working with streams, writers and readers, do some study on these before working with JSch.

SSH Output always empty

I've been trying to figure out this problem for hours now and I cant seem to figure it out. I'm trying to use JSch to SSH to a Linux computer from an Android phone. The commands always work fine but the output of the channel is usually empty. Sometimes it displays the output but most of the time it doesn't. Here's the code that I found online.
String userName = "user";
String password = "test123";
String connectionIP = "192.168.1.13";
JSch jsch = new JSch();
Session session;
session = jsch.getSession(userName, connectionIP, 22);
session.setPassword(password);
// Avoid asking for key confirmation
Properties prop = new Properties();
prop.put("StrictHostKeyChecking", "no");
session.setConfig(prop);
session.connect();
// SSH Channel
ChannelExec channelssh = (ChannelExec) session.openChannel("exec");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
channelssh.setOutputStream(baos);
// Execute command
channelssh.setCommand("ls");
channelssh.connect();
channelssh.disconnect();
RESULT = baos.toString();
RESULT is usually empty. If I change the command to mkdir or something of that nature the files show up on the Linux computer which leads me to believe that the command part is working correctly. The problem seems to lie within the ByteArrayOutputStream. I've also tested the connectionip, username and password on a different computer through Terminal so I know the credentials are correct. I've Googled this problem to death, any input would help me out significantly!
Found the answer I was reading the wrong stream. Heres the proper code for others with this problem.
InputStream inputStream = channelssh.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder stringBuilder = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null)
{
stringBuilder.append(line);
stringBuilder.append('\n');
}
return stringBuilder.toString();
The exec-channel will be run on the other thread, so you need to wait for its termination before invoking Channel#disconnect().

Categories