Ganymed SSH-2 for Java是一个纯Java实现的SHH2库,官网为http://www.ganymed.ethz.ch/ssh2/,最新的更新时间为2006年10月,在用之前,请仔细看一下FAQ,真的能避免很多很多问题,下面列出几条重要的:

一,如果使用Session.execCommand()方法,则每个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");//这么写是不行的

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("Here is the output from stdout:");

while (true) {

String line = stdoutReader.readLine();

if (line == null)

break;

System.out.println(line);

}

System.out.println("Here 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);

}

}

}

执行结果为:

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 use Session.execCommand(), then you indeed can only execute only one command per session. This is not a restriction of the library, but rather an enforcement by the underlying SSH-2 protocol (a Session object models 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 again")一批次执行多条命令

sess.execCommand("cd test;cat 1.txt");

2,Simple: The intended way: simply open a new session for each command - once you have opened a connection, you can ask for as many sessions as you want, they are only a "virtual" construct为每一个命令打开一个新的会话

Session sess = conn.openSession();

sess.execCommand("cd test");//进入~/test路径

sess.close();

sess = conn.openSession();//由于是新打开的会话,此时在~路径下

sess.execCommand("cat 1.txt");

由于每个命令执行完成后会话会关闭,所以在执行"cat 1.txt"时会报找不到该文件,因为第二次登陆成功后在~路径下,而1.txt文件在~/test路径下

3,Advanced: Don't use Session.execCommand(), but rather aquire a shell with Session.startShell()使用Session.startShell()方法代替Session.execCommand()方法

二,如果使用Sess.execCommand()得到的结果和预期不一样或根本不能执行,那么要注意你的环境变量

The most often source of problems when executing a command with Session.execCommand() are missing/wrong set environment variables on the remote machine. Make sure that the minimum needed environment for XYZ is 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 the file ~/.bash_profile only contains the 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.

在~/test/路径下准备一个test.sh脚本:

#!/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 started"

fi

fi

然后尝试调用这个脚本:

sess.execCommand("sh -x ~/test/test.sh start");

运行结果如下:

Here is the output from stdout:

opt:start

service iptables already started

Here is the output from stderr:

+ opt=start

+ '[' startx = startx ']'

+ echo opt:start

++ lsmod

/home/hadoop/test/test.sh:行6: lsmod: 未找到命令

++ grep ip_tables

++ wc -l

+ status=0

+ '[' 0 -gt 0 ']'

+ echo 'service iptables already started'

可以看到脚本打印信息由stdout输出,脚本-x的调试信息由stderr输出,脚本在虚拟机中运行正常,为什么这里却提示"lsmd:未找到命令"呢

虚拟机中的环境变量如下:

[hadoop@localhost test]$ echo $PATH

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/bin:/sbin

再来看看代码中建立的会话的环境变量:

sess.execCommand("echo $PATH");Here is the output from stdout:

/usr/local/bin:/usr/bin

Here is the output from stderr:

相差十万八千里,反正我是懒得整了,咱就直接全路径吧,将脚本中的lsmod修改为/usr/sbin/lsmod

三,当我只从stdout中读取数据时,进程有时候会挂起

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

在底层SSH2协议中,每个channel(写过socket的应该都知道这个是什么)都有一个接收窗,当远程的SSH进程填充满我们的接收窗,在我们消耗掉接收窗中的数据并可以接收新的数据之前它都会处于等待状态

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 you never consume it, then after some time the local receive window will be full and

the sender is blocked. If you then try to read() from stdout, your call will be blocked: there is no stdout data (locally) available and the SSH daemon cannot send you any, since the receive window is full (you would have to read some stderr data first to

"free" up space in the receive window).

不幸的是,底层SSH2协议为stdout和stderr定义了一个共享的接收窗,如果远程的SSH进程产生了很多stderr信息但是你从来都没有消费过它们,一段时间后,本地的接收窗将被填满,此时数据发送端将被挂起,如果这时你试图读取stdout,你的请求也将被挂起。由于接收窗已满,因此接收窗中没有任何可用的stdout信息,并且远程SSH进程也不会发送任何stdout信息(除非先读取一些stderr信息以释放部分接收窗的空间)

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

幸运的是,Ganymed SSH-2使用30KB大小的接收窗,所以上面描述的情景很少发生

Many other SSH-2 client implementations just blindly consume any remotely produced data into a buffer which gets automatically extended - however, this can lead to another problem: in the extreme case the remote side can overflow you with data (e.g., leading

to out of memory errors).

What can you do about this?

1,Bad: Do nothing - just work with stderr and stdout Inputstreams and hope that the 30KB window is enough for your application. 啥也不做,期盼30KB足够程序使用

2,Better, recommended for most users: use two worker threads that consume remote stdout and stderr in parallel. Since you probably are not in the mood to program such a thing, you can use the StreamGobbler class supplied

with Ganymed SSH-2. The Streamgobbler is a special InputStream that uses an internal worker thread to read and buffer internally all data produced by another InputStream. It is very simple to use:

只需使用Ganymed SSH-2自带的StreamGobbler类即可使用2个工作线程并行消费远程的stdout和stderr,StreamGobbler是一个特殊的输入流,它能使用内部工作线程读取、缓存所有另一个输入流输入的信息,示例如下:

InputStream stdout = new StreamGobbler(mysession.getStdout());

InputStream stderr = new StreamGobbler(mysession.getStderr());

You then can access stdout and stderr in any order, in the background the StreamGobblers will automatically consume all data from the remote side and store in an internal buffer.

然后你就可以以任何顺序访问stdout和stderr,StreamGobblers将会在后台自动消费所有远程端口传递过来的数据并存放在一个内部的buffer中

3,Advanced: you are paranoid and don't like programs that automatically extend buffers without asking you. You then have to implement a state machine. The condition wait facility offered by Session.waitForCondition() is exactly what you need: you can use

it to wait until either stdout or stderr data has arrived and can be consumed with the two InputStreams. You can either use the return value of Session.waitForCondition() or check with InputStream.available() (for stdout and stderr) which InputStream has data

available (i.e., a read() call will not block). Be careful when wrapping the InputStreams, also do not concurrently call read() on the InputStreams while calling Session.waitForCondition() (unless you know what you are doing).

Sess.waitForCondition方法可以获取流的状态信息,通过得到的状态信息来判断下一步做什么

接下来遇到的问题相当的棘手,反正我是没查到问题的原因,当我在项目中使用Ganymed SSH-2调用服务器脚本的时候,进程经常会卡主(不是所有的脚本,少部分脚本,但是我没发现产生异常的脚本和可以正常调用的脚本之间有什么不同,并且可以确定,绝对不是接收窗满引起的,因为只返回了很少的运行结果,并且debug时也可以看到,BufferedReader中创建的长度为8000多的字符数组只被使用了几百的空间),奇怪的是如果我把脚本调用部分单独提取出来放到一个Java项目中执行,运行正常

脚本最后部分如下:

......

if [ -n "$pid" ]

then

echo "success"

exit 0

else

echo "faild."

exit -1

fi

fi

fi

代码如下(程序第一次进入while循环时打出success,第二次进入循环后,在String line = stdoutReader.readLine();这一步卡主):

......

BufferedReader stderrReader = new BufferedReader(

new InputStreamReader(stderr));

System.out.println("Here is the output from stdout:");

while (true) {

String line = stdoutReader.readLine();

if (line == null)

break;

System.out.println(line);

}

......

日志如下:

......

Here is the output from stdout:

success

由于Java源代码调试起来很费劲,最终也没调试问题出在哪里,介绍下解决方式吧,虽然程序进程卡住了,但是后台的脚本其实已经成功运行完成,所以要做的就是为连接返回结果的读取设置超时时间

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;//超时后退出循环,要保证超时时间内,脚本可以运行完成

}

if ((conditions & ChannelCondition.EOF) != 0) {

if ((conditions & (ChannelCondition.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);

}

}

}

反正我以后是不准备用这个东西了

ganymed ssh-2 for java_Ganymed SSH-2 for Java相关推荐

  1. python实现ssh登录send_Python实现ssh批量登录并执行命令

    局域网内有一百多台电脑,全部都是linux操作系统,所有电脑配置相同,系统完全相同(包括用户名和密码),ip地址是自动分配的.现在有个任务 是在这些电脑上执行某些命令,者说进行某些操作,比如安装某些软 ...

  2. linux ssh 设置的相关总结(ssh最大连接数、ssh连接时长、安全性配置等)

    以redhat6.3为例 ssh配置文件在: //ssh/sshd_config 可以打开查看相应配置,默认情况下只开放了几个选项,其余全部#屏蔽掉了. 英文手册参考:http://www.openb ...

  3. oracle ssh测试不通过,ssh 连接不上 oracle linux 7.2

    问题描述 oralce linux 可以ssh到其他设备,可是其他设备ssh不上oracle linux ssh username@hostip -v OpenSSH_6.6.1,OpenSSL 1. ...

  4. ubuntu下查询SSH状态和安装SSH服务

    1.查询SSH的安装状态 rpm -qa |grep ssh 上面的命令可能出现提示说rpm未安装,可以使用下面这命令进行安装 sudo apt-get install rpm 某些帖子上也可以使用y ...

  5. ssh key生成_Stelnet(ssh)登陆华为交换机配置教程

    使用STelnet V1协议存在安全风险,建议使用STelnet V2登录设备. 1.生成本地密钥对 密钥保存在交换机中单不保存在配置文件中 [Huawei]rsa ? key-pair RSA ke ...

  6. linux ssh密钥对,Mac使用ssh密钥登录Linux

    ssh登录Linux通常有两种方法:用户名密码登录.用户名密钥登录:使用用户名密码登录每次都要输入密码,相当麻烦,而使用用户名密钥登录则可以避免这个问题. 创建密钥对文件 打开本地终端,执行 ssh- ...

  7. 实现 SSH 无密码登录 、 ssh 常用命令

    OpenSSH是互联网技术用户所依赖的SSH连接工具的免费版本. telnet,rlogin 和 ftp 用户可能没有意识到他们的密码是通过互联网传输的,并且是未加密的. 但是 OpenSSH 加密所 ...

  8. arm9重启ssh服务_部署ssh使用rsa登录配置

    什么是ssh? ssh专为远程登录会话和其他网络服务提供安全性的协议,利用ssh协议可以有效的防止远程管理过程中的信息泄露问题. 使用ras公钥登录linux 操作环境 本地服务器:win10 远程服 ...

  9. git 生成ssh key_ubuntu git生成ssh key (公钥私钥)配置github或者码云

    Git是分布式的代码管理工具,远程的代码管理是基于SSH的,所以要使用远程的Git则需要SSH的配置. github的SSH配置如下: 设置Git的user name和email: git confi ...

  10. linux 谷歌浏览器设置代理_linux下chrome+Proxy Switchy+ssh和firefox+autoproxy+ssh | 学步园...

    继之前firefox+autoproxy+tor+privoxy失效之后,找到了更简单更快速的ssh代理方法:chrome+Proxy Switchy+ssh和firefox+autoproxy+ss ...

最新文章

  1. 【PHPWord】图片
  2. futuretask java 并发请求_图文并茂理解 Java 多线程
  3. linux中mongo的导出数据,Linux下mongodb安装及数据导入导出教程(示例代码)
  4. 爬虫代理及ssl验证
  5. 从Windows上用SSH链接接入Ubuntu
  6. 汇编语言学习系列 for循环实现
  7. [python进阶]11接口:从协议到抽象基类
  8. 从GlassFish 3.x扩展到WebLogic 12c Server
  9. Java知识积累-基础篇
  10. ssm架构 开源项目_如何为您的开源项目选择正确的品牌架构
  11. nodejs 连接数据库 并在数据库上进行增删改查操作
  12. 软件行业装机卖软件模式没落 转型SaaS服务趋势明显
  13. 字节跳动校招 抖音电商前端 三面面经
  14. 全球与中国农用软管卷盘市场现状及未来发展趋势
  15. 如何分析关键词的优化难度?
  16. github-一个视频图片下载工具-lux(annie)
  17. java properties 遍历_如何遍历properties文件的键值对并放置到application作用域里
  18. 了解文件系统调用吗?如何实现的?
  19. 【编程杂谈】【书单】-陈皓大佬推荐书单
  20. Jina 实例秀|基于神经搜索的网络安全威胁检测(一)

热门文章

  1. 孙志华老师担任第十四届世界易学大会副主席一职
  2. 计算机机房双电源供电,综合布线系统设备间供配电方式有几种,各有什么具体的要求...
  3. unity3d学习笔记-光照(1.一些概念)
  4. CSS中的flax布局
  5. 【初级篇】独立开发者 5 分钟入门 App 营销
  6. 1角5角荧光参照表转自南海老黄
  7. 【POJ 1286】Necklace of Beads(polya定理)
  8. 关于C#中的隐藏方法的使用
  9. python url解析_Python中实现URL的解析
  10. VSLAM:一:VSLAM小科普