最近在公司项目中,需用java远程连接linux服务器。最终选定了用jsch的方式。但在实现的过程中遇到两个问题。
①通过jsch的exec通道时,执行su命令会异常开始,原因是因为执行su命令后返回的结果标准化输出后为空,所以异常卡死;最后放弃此种方式改用shell通道
②使用jsch的shell通道时,如何获取到返回结果。通过readline的方式读取时执行su依旧会进入死循环,最后决定通过读取字节码的方式来获取返回结果,通过字节码的方式读取时又遇到终端显示字体颜色的乱码问题,通过设置伪终端的方式解决。
一下为解决的代码:
首先创建会话:
public static Session createSession(String OSIP, String OSUserName, String OSPassword){
Session session = null;
JSch jsch = new JSch();
try {
// 通过jsch创建一个会话
session = jsch.getSession(OSUserName, OSIP, port);
// 设置会话自动传输密码
session.setPassword(OSPassword);
// 创建Properties类
Properties config = new Properties();
// 设置第一次登录不验证密码
config.put("StrictHostKeyChecking", "no");
// 设置公钥和私钥
config.put("PreferredAuthentications", "publickey,keyboard-interactive,password");
// 导入会话设置
session.setConfig(config);
// 设置会话超时时间
session.setTimeout(timeOut);
Log.printLog("ssh连接" + OSIP);
// 连接上目标IP的会话
session.connect();
//代码调试,信息打印
//System.out.println("username"+session.getUserName()+session.isConnected());
} catch (JSchException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return session;
}
建议交互式shell通道:
public static ChannelShell createChannelShell(Session session) {
ChannelShell channelShell = null;
try {
Channel channel = session.openChannel("shell");
channelShell = (ChannelShell) channel;
//解决终端高亮显示时颜色乱码问题
channelShell.setPtyType("dump");
channelShell.setPty(true);
channelShell.connect();
Log.printLog("与" + session.getHost() + "的SHELL通道建立成功");
} catch (JSchException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return channelShell;
}
执行命令:
public static String execShellCmd(ChannelShell channelShell, String command, int sleepTime){
StringBuffer sBuffer = new StringBuffer();
int beat = 0;
String result = "";
String endResult = "";
try {
// 远端界面返回
InputStream in = channelShell.getInputStream();
// 本地内容推送到远端
OutputStream out = channelShell.getOutputStream();
// 要执行命令后加换行符才可以执行
String execCommand = command + changeLine;
Log.printLog("要执行的命令:" + command);
// 写入执行命令
out.write(execCommand.getBytes());
// 清空缓存区,开始执行
out.flush();
Thread.sleep(sleepTime);
while (true) {
if (beat > 3) {
break;
}
if (in.available() >0 ) {
//InputStream按位读取,并保存在stringbuffer中
byte[] bs =new byte[in.available()];
in.read(bs);
sBuffer.append(new String(bs));
beat ++;
}else {
if (sBuffer.length() >0) {
beat++;
}
}
}
// 将stringbuff读取的InputStream数据,转换成特定编码格式的字符串,一般为UTF-8格式
result = new String(sBuffer.toString().getBytes(charsetName));
// 将返回结果,按行截取并放进数组里面
String[] strings = result.split(changeLine);
// 通过遍历,筛选无意义的字符
for (int i = 1; i < strings.length; i++) {
if (!strings[i].contains("#") && !strings[i].contains(command) &&
!strings[i].contains("$") && !strings[i].contains(">")) {
//获取筛选后的字符
endResult = endResult+strings[i] +changeLine;
}
}
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
Log.printLog("命令执行完,返回的结果为:" + endResult);
return endResult;
}
其实在结果返回的处理这部分。代码逻辑有点混乱。但是能用。感觉处理的不是很好。也请各位帮忙能优化下。