package com.example.demo;
import com.jcraft.jsch.ChannelShell;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UserInfo;
import expect4j.Closure;
import expect4j.Expect4j;
import expect4j.ExpectState;
import expect4j.matches.EofMatch;
import expect4j.matches.Match;
import expect4j.matches.RegExpMatch;
import expect4j.matches.TimeoutMatch;
import org.apache.log4j.Logger;
import org.apache.oro.text.regex.MalformedPatternException;
import org.springframework.util.StringUtils;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
public class Shell {
private static Logger log = Logger.getLogger(Shell.class);
private Session session;
private ChannelShell channel;
private static Expect4j expect = null;
private static final long defaultTimeOut = 1000;
private StringBuffer buffer = new StringBuffer();
public static final int COMMAND_EXECUTION_SUCCESS_OPCODE = -2;
public static final String BACKSLASH_R = "\r";
public static final String BACKSLASH_N = "\n";
public static final String COLON_CHAR = ":";
public static String ENTER_CHARACTER = BACKSLASH_R;
public static final int SSH_PORT = 22;
//正则匹配,用于处理服bai务du器返回的zhi结果
public static String[] linuxPromptRegEx = new String[]{"~\\]#", "~#", ":~#", "/\\$", "\\>"};
public static String[] linuxMoreRegEx = new String[]{"--More"};
public static String[] errorMsg = new String[]{"could not acquire the config lock "};
//ssh服务器的ip地址
private String ip;
//ssh服务器的登入端口dao
private int port;
//ssh服务器的登入用户名
private String user;
//ssh服务器的登入密码
private String password;
public Shell(String ip, int port, String user, String password) {
this.ip = ip;
this.port = port;
this.user = user;
this.password = password;
expect = getExpect();
}
/*** 关闭SSH远程连接*/
public void disconnect() {
if (channel != null) {
channel.disconnect();
}
if (session != null) {
session.disconnect();
}
}
/*** 获取服务器返回的信息* @return 服务端的执行结果*/
public String getResponse() {
return buffer.toString();
}//获得Expect4j对象,该对用可以往SSH发送命令请求
private Expect4j getExpect() {
try {
log.debug(String.format("Start logging to %s@%s:%s", user, ip, port));
JSch jsch = new JSch();
session = jsch.getSession(user, ip, port);
session.setPassword(password);
Hashtable<String, String> config = new Hashtable<String, String>();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
localUserInfo ui = new localUserInfo();
session.setUserInfo(ui);
session.connect();
channel = (ChannelShell) session.openChannel("shell");
Charset.defaultCharset();
Expect4j expect = new Expect4j(channel.getInputStream(), channel.getOutputStream());
channel.connect();
log.debug(String.format("Logging to %s@%s:%s successfully!", user, ip, port));
return expect;
} catch (Exception ex) {
log.error("Connect to " + ip + ":" + port + "failed,please check your username and password!");
ex.printStackTrace();
}
return null;
}
/*** 执行配置命令* @param commands 要执行的命令,为字符数组* @return 执行是否成功*/
public boolean executeCommands(String[] commands) {//如果expect返回为0,说明登入没有成功
if (expect == null) {
return false;
}
log.debug("----------Running commands are listed as follows:----------");
for (String command : commands) {
log.debug(command);
}
log.debug("----------End----------");
List<Match> lstPattern = sshMatch();
try {
boolean isSuccess = true;
for (String strCmd : commands) {
isSuccess = isSuccess(lstPattern, strCmd);
}
//防止最后一个命令执行不了
isSuccess = !checkResult(expect.expect(lstPattern));
//找不到错误信息标示成功
String response = buffer.toString().toLowerCase();
for (String msg : errorMsg) {
if (response.indexOf(msg) > -1) {
return false;
}
}
return isSuccess;
} catch (Exception ex) {
ex.printStackTrace();
return false;
}finally {
if (expect!=null) {
expect.close();
}
}
}
private List<Match> sshMatch(){
List<Match> lstPattern = new ArrayList<Match>();
String[] regEx = linuxPromptRegEx;
if (regEx != null && regEx.length > 0) {
synchronized (regEx) {
for (String regexElement : regEx) {
try {
RegExpMatch mat = new RegExpMatch(regexElement, new EndClosure(buffer));
lstPattern.add(mat);
} catch (MalformedPatternException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
for (String regexElement : linuxMoreRegEx){
try {
RegExpMatch mat = new RegExpMatch(regexElement, new MoreClosure(buffer, expect));
lstPattern.add(mat);
} catch (MalformedPatternException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
lstPattern.add(new EofMatch(new Closure() {
@Override
public void run(ExpectState state) {
}
}));
lstPattern.add(new TimeoutMatch(defaultTimeOut, new Closure() {
@Override
public void run(ExpectState state) {
}
}));
}
}
return lstPattern;
}
//检查执行是否成功
private boolean isSuccess(List<Match> objPattern, String strCommandPattern) {
try {
boolean isFailed = checkResult(expect.expect(objPattern));
if (!isFailed) {
expect.send(strCommandPattern);
expect.send(BACKSLASH_R);
return true;
}
return false;
} catch (MalformedPatternException ex) {
return false;
} catch (Exception ex) {
return false;
}
}
//检查执行返回的状态
private boolean checkResult(int intRetVal) {
if (intRetVal == COMMAND_EXECUTION_SUCCESS_OPCODE) {
return true;
}
return false;
}
//登入SSH时的控制信息//设置不提示输入密码、不显示登入信息等
public static class localUserInfo implements UserInfo {
String passwd;
@Override
public String getPassword() {
return passwd;
}
@Override
public boolean promptYesNo(String str) {
return true;
}
@Override
public String getPassphrase() {
return null;
}
@Override
public boolean promptPassphrase(String message) {
return true;
}
@Override
public boolean promptPassword(String message) {
return true;
}
@Override
public void showMessage(String message) {
}
}
public static void main(String[] args) {
Shell shell = new Shell("192.168.234.163", 22, "root", "zhang");
List<String> list = new ArrayList<>();
list.add("ss ");
shell.executeCommands(list.toArray(new String[list.size()]));
log.info(shell.getResponse());
shell.disconnect();
}
public static String removeCharB(String str){
if(StringUtils.isEmpty(str)){
return str;
}
String [] strArr = str.split("\b+");
return strArr[strArr.length-1].trim() + BACKSLASH_R;
}
public static String removeCharRN(String str){
if(StringUtils.isEmpty(str)){
return str;
}
return str.substring(0, str.lastIndexOf("\r\n")).trim();
}
}
class EndClosure implements Closure{
private StringBuffer buffer;
public EndClosure(StringBuffer buffer) {
this.buffer = buffer;
}
@Override
public void run(ExpectState state) throws Exception {
buffer.append(Shell.removeCharB(state.getBuffer()));
}
}
//当检测到more时发送空格,并持续接收
class MoreClosure implements Closure{
private StringBuffer buffer;
private Expect4j expect;
public MoreClosure(StringBuffer buffer, Expect4j expect) {
this.buffer = buffer;
this.expect = expect;
}
@Override
public void run(ExpectState state) throws Exception {
buffer.append(Shell.removeCharB(Shell.removeCharRN(state.getBuffer())));
expect.send(" ");
state.exp_continue();
}
}