Ganymed SSH-2 for Java__java

Source: Internet
Author: User
Tags readline iptables

Ganymed SSH-2 for Java is a pure Java implementation of the SHH2 Library, the official website for http://www.ganymed.ethz.ch/ssh2/, the latest update time for October 2006, before using, please take a closer look at the FAQ, Can really avoid a lot of problems, here are a few important:

One, if you use the Session.execcommand () method, you can only execute one command per session

Import Java.io.BufferedReader;
Import java.io.IOException;
Import Java.io.InputStream;

Import Java.io.InputStreamReader;
Import ch.ethz.ssh2.Connection;
Import ch.ethz.ssh2.Session;
Import Ch.ethz.ssh2.StreamGobbler;
		public class Sshtest {public static void main (string[] args) {String hostname = "192.168.192.130";
		String username = "Hadoop";

		String password = "Hadoop";
			try {Connection conn = new Connection (hostname);
			Conn.connect ();
			Boolean isauthenticated = Conn.authenticatewithpassword (Username,password);
			if (isauthenticated = false) throw new IOException ("Authentication failed.");
			
			Session Sess = Conn.opensession ();

			Sess.execcommand ("CD test");//This is not a good Sess.execcommand ("Cat 1.txt");
			InputStream stdout = new Streamgobbler (Sess.getstdout ());
			InputStream stderr = new Streamgobbler (Sess.getstderr ());
			BufferedReader stdoutreader = new BufferedReader (new InputStreamReader (stdout)); BufferedReader Stderrreader = new BuffeRedreader (New InputStreamReader (stderr));
			System.out.println ("This is the output from stdout:");
				while (true) {String line = Stdoutreader.readline ();
				if (line = = null) break;
			System.out.println (line);
			} System.out.println ("This is the output from stderr:");
				while (true) {String line = Stderrreader.readline ();
				if (line = = null) break;
			System.out.println (line);
			} sess.close ();
		Conn.close ();
			catch (IOException e) {e.printstacktrace (system.err);
		System.exit (2); }
	}
}

The results of the execution are:

JAVA.IO.IOEXCEPTION:A remote execution has already started.
	At Ch.ethz.ssh2.Session.execCommand (session.java:244) at
	Sshtest.main (sshtest.java:28)

If you are Session.execcommand (), then you indeed can only execute one command per session. This isn't a restriction of the library, but rather a enforcement by the underlying SSH-2 protocol (a Session object MoD Els the underlying SSH-2 session).

There are several solutions:

1,simple:execute several commands in one batch, e.g., something like Session.execcommand ("Echo Hello && echo Agai n ") a batch of times to execute more than one command

Sess.execcommand ("CD Test;cat 1.txt");

2,simple:the intended way:simply open a new session for each command-once your have opened a connection, you can ask Fo R as many sessions as your want, they are only a "virtual" construct open a new session for each command

Session Sess = Conn.opensession ();
Sess.execcommand ("CD test");//Enter ~/test path
sess.close ();
Sess = Conn.opensession ();//Because it is a newly opened session, at this time
Sess.execcommand ("Cat 1.txt") under the ~ path;

Because the session closes after each command completes, the file cannot be found when executing "cat 1.txt" because the second login succeeds in the ~ path, and the 1.txt file is under the ~/test path

3,advanced:don ' t use Session.execcommand (), but rather aquire-a shell with Session.startshell () using Session.startshell () Method instead of the Session.execcommand () method

Two, if you use Sess.execcommand () and the results are not as expected or can not be implemented at all, then pay attention to your environment variables

The most often source of problems when executing a command with Session.execcommand () are missing/wrong set environment VA Riables on the remote machine. Make sure this minimum needed environment for XYZ are the same, independentely on how the shell is being invoked.

Example quickfix for bash users:

1,define all your settings in the file ~/.BASHRC

2,make sure that "file ~/.bash_profile only contains" linesource ~/.BASHRC

3,before executing Session.execcommand (), do not aquire any type of pseudo terminal in the session. Be prepared to consume stdout and stderr data.

Prepare a test.sh script under the ~/test/path:

#!/bin/sh
opt=$1
if [${opt}x = StartX]
        then
        echo "Opt:start" status=
        ' lsmod | grep ip_tables | wc-l '
        if [${status}-gt 0]
        then
                sudo service iptables start
        else
                Echo service Iptables already "
        fi
fi

Then try calling this script:

Sess.execcommand ("Sh-x ~/test/test.sh start");

The results of the operation are as follows:

This is the output from stdout:
opt:start
Service Iptables already started this is the
output from stderr:
  
   + opt=start
+ ' [' StartX = StartX ']
+ echo Opt:start
+ + lsmod/home/hadoop/test/test.sh
: line 6:lsmod: Not found Command
+ + grep ip_tables + +
wc-l
+ status=0
+ ' [' 0-gt 0 '] '
+ echo ' service Iptables already started '
  

You can see the script printing information by stdout output, script-X debugging information by the STDERR output, the script in the virtual machine running normally, why here is prompted "LSMD: Not found command"?

The environment variables in the virtual machine are as follows:

[Hadoop@localhost test]$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/bin:/ Sbin

Take a look at the environment variables for the session you established in your code:

Sess.execcommand ("Echo $PATH");
Here are the output from stdout:
/usr/local/bin:/usr/bin are the
output from stderr:

Difference 108,000, anyway, I am too lazy to complete, I direct full path, the script in the Lsmod modified to/usr/sbin/lsmod

third, when I read data only from STDOUT, the process sometimes hangs

In the SSH-2, protocol, each channel (e.g., session) has a receive window. When the remote SSH daemon has filled up our receive windows, it must wait until we have consumed the input and are ready t o Accept new data.

In the underlying SSH2 protocol, each channel (a socket should know what it is) has a receive window, and when the remote SSH process fills our receive window, it waits until we consume the data in the receiving window and receive new data.

Unfortunately, the SSH-2 protocol defines a shared window for stderr and stdout. As a consequence, if, for example, the remote process produces a lot of stderr data and your never consume it, then after S ome time the local receive window would be full and the sender is blocked. If you are then try to read () in stdout, your call'll be Blocked:there is no stdout data (locally) available and the SSH Daemon cannot send to all, since the Receive window is full (for you would have to read some stderr data the ' free ' up s Pace in the Receive window).

Unfortunately, the underlying SSH2 protocol defines a shared receive window for stdout and stderr, if the remote SSH process produces a lot of stderr information but you never consume them, and after a while the local receive window will be filled, and the data sender will be suspended, If you attempt to read stdout, your request will also be suspended. Because the receive window is full, there is no stdout information available in the Receive window, and the remote SSH process will not send any stdout information (unless some stderr information is first read to free up some of the receiving window)

Fortunately, Ganymed SSH-2 uses a 30KB window-the above described scenario the should be very rare.

Fortunately, the Ganymed SSH-2 uses a 30KB-size receive window, so the scenario described above rarely occurs

Many Other SSH-2 client implementations just blindly consume no remotely produced data into a buffer which gets automatic Ally Extended-however, this can leads to another problem:in the extreme case the remote side can overflow your with data (e.g., leading to out of memory errors).

What can do about this?

1,bad:do nothing-just work with stderr and stdout inputstreams and hope to the 30KB window is enough for your tion. Do nothing, look forward to 30KB enough program to use

2,better, recommended for most users:use two worker threads-consume remote stdout and stderr in parallel. Since you probably are the "mood to" program such a thing, can use the Streamgobbler class supplied with ganymed SSH-2. The Streamgobbler is a special InputStream this uses a internal worker thread to read and buffer internally all data prod Uced by another inputstream. It is very simple to use:

Just use the Streamgobbler class with the ganymed SSH-2 to consume 2 worker threads in parallel consumption remote stdout and Stderr,streamgobbler is a special input stream that can be read using internal worker threads, The information that is cached for all other input streams is as follows:

InputStream stdout = new Streamgobbler (Mysession.getstdout ());
InputStream stderr = new Streamgobbler (Mysession.getstderr ());

You then can access stdout and stderr into any order, in the background the streamgobblers'll automatically all DA Ta from the remote side and store in a internal buffer.

Then you can access stdout and stderr,streamgobblers in any order in the background to automatically consume all the remote-handed pass data and store it in an internal buffer.

3,advanced:you are paranoid and don ' t like programs, automatically extend buffers without you. You are then have to implement a state machine. The condition wait facility offered by Session.waitforcondition () are exactly what you need:you can-use it to-wait until E Ither stdout or stderr data has arrived and can is consumed with the two inputstreams. Can either use the ' return value ' of session.waitforcondition () or check with inputstream.available () (for StdOut and St DERR) which InputStream has data available (i.e., a read () call to won't block). Is careful when wrapping the inputstreams, also does not concurrently call read () on the Inputstreams while calling session. Waitforcondition (unless) (Know what you are doing).

The Sess.waitforcondition method can obtain the state information of the stream and determine what to do next by the state information obtained.

The next problem is quite tricky, anyway, I didn't find the cause of the problem, and when I used ganymed SSH-2 to invoke the server script in my project, the process would always be card master (not all scripts, little scripts, but I didn't see any difference between the script that generated the exception and the script that would normally be invoked. , and it can be determined that it is definitely not a receive window full because only a very small number of running results are returned, and as you can see in debug, the 8,000-BufferedReader character array created in the box is only used for hundreds of of the space. The odd thing is that if I pull the script call part out and put it in a Java project, it works.

The final part of the script is as follows:

......
                If [-N "$pid"]
                then
                        echo "Success"
                        exit 0
                Else
                        echo "faild."
                        Exit-1
                fi fi fi

The code is as follows (when the program first enters the while loop, it success, the second enters the loop, after the string line = Stdoutreader.readline (); This step card master):

......
BufferedReader stderrreader = new BufferedReader (
		new InputStreamReader (stderr));
			
System.out.println ("This is the output from stdout:");
while (true) {
	String line = Stdoutreader.readline ();
	if (line = = null) break
		;
	System.out.println (line);
......

The log is as follows:

......
Here's the output from stdout:
success

Because the Java source code debugging is very laborious, finally did not debug the problem where, introduce the solution, although the program process is stuck, but the background of the script has been successfully completed, so to do is for the connection return the result of the read set timeout time

InputStream stdout = Sess.getstdout ();
	            
InputStream stderr = Sess.getstderr ();
byte[] buffer = new BYTE[100];
String result = ""; 
	  		while (true) {if ((stdout.available () = = 0)) {int conditions = Sess.waitforcondition (Channelcondition.stdout_data | Channelcondition.stderr_data |
		Channelcondition.eof, 1000*5);
			if ((Conditions & Channelcondition.timeout)!= 0) {logger.info ("Time Out Break"); break;//timeout After the loop, to ensure that the timeout period, the script can run completed} if ((Conditions & channelcondition.eof)!= 0) {if (Conditions & (Ch 
	  			Annelcondition.stdout_data |
				channelcondition.stderr_data) = = 0) {Logger.info ("break");
			Break
    }} while (Stdout.available () > 0) {int len = stdout.read (buffer);
			if (Len > 0) {System.err.write (buffer, 0, Len);
		Result + = new String (buffer, 0, Len);
		} while (stderr.available () > 0) {int len = stderr.read (buffer); if (Len > 0) {System.err.write(buffer, 0, Len);
		Result + = new String (buffer, 0, Len);
 }
	}
}

Anyway, I'm not going to use this stuff anymore

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.