轉載自https://www.cnblogs.com/ArcherWuAIot/p/12790486.html
JSch 是SSH2的一個純Java實現。它允許通過代碼的方式連接到一個sshd 服務器,使用端口轉發,X11轉發,文件傳輸等等。可以將它的功能集成到自己寫的程序中。實現一個java工具類。
SSH由客戶端和服務端的軟件兩部分組成,在客戶端可以使用的軟件有SecureCRT、putty、Xshell等,而在服務器端運行的是一個sshd的服務,通過使用SSH,可以把所有傳輸的數據進行加密,而且也能夠防止dns和IP欺騙,此外,SSH傳輸的數據是經過壓縮的,可以加快傳輸速度。服務器端的配置文件路徑: /etc/ssh/sshd_config
spring-boot引用:
dependencies { compile group: 'com.jcraft', name: 'jsch', version: '0.1.55' }
代碼里的命令調用:
try { String result = clusterCommondService.execOnly( "xxxxxxxxx " + name + " xxxx" + "\n"); } catch (Exception e) { log.error("Error when init :", e); return null; }
java代碼實現
@Slf4j
@Service
public class ClusterCommondService {
@Value("${cluster.pemPrivateKey}")
protected String pemPrivateKey;
@Value("${cluster.port}")
protected int port;
@Value("${cluster.user}")
protected String user;
//寫在配置文件里的配置值
@Autowired
private ClusterIpUtil clusterIpUtil;
//連接的IP
private Session session = null;
private boolean bConnect = false;
//默認第一次是false,先建立連接
protected String ip;
private void initConnection() throws JSchException {
ip = clusterIpUtil.getClusterIp();
String begin = "-----BEGIN RSA PRIVATE KEY-----";
String end = "-----END RSA PRIVATE KEY-----";
String a = pemPrivateKey.replace(" ", "\n");
String privateKey = begin + "\n" + a + "\n" + end;
JSch jsch = new JSch();
jsch.addIdentity(user, privateKey.getBytes(), null, null);
session = jsch.getSession(user, ip, port);
session.setConfig("PreferredAuthentications", "publickey");
session.setConfig("StrictHostKeyChecking", "no");
session.setConfig("userauth.gssapi-with-mic", "no");
session.setConfig("UserKnownHostsFile", "/dev/null");
session.setServerAliveCountMax(3);
//連接三次,連不上就不連接了
session.connect();
bConnect = true;
}
//設置連接信息,應該是代替了客戶端的/etc/ssh/ssh_config
public String exec(String cmd) throws JSchException, IOException {
if (!bConnect) {
initConnection();
}
ChannelExec channelExec = (ChannelExec) session.openChannel("exec");
//使用exec方式建立連接(補充,jsch跑命令分兩種方式,一種是exec,一種是sftp;從遠端拿文件或者向遠端傳文件的話用sftp,跑命令然后拿返回值的話用exec)
channelExec.setCommand(cmd);
//把命令放進連接里
channelExec.setInputStream(null);
channelExec.setErrStream(System.err);
//設置輸入流和錯誤信息流,清空輸入流
InputStream in = channelExec.getInputStream();
//建一個in是輸入流
channelExec.connect();
//建立連接,和遠端建立連接之后上面的命令就自動執行了(此時的in里面就有返回值了)
int res = -1;
StringBuilder buf = new StringBuilder(1024);
byte[] tmp = new byte[1024];
while (true) {
while (in.available() > 0) {
int i = in.read(tmp, 0, 1024);
if (i < 0) break;
//這如果讀不到了,就說明讀完了命令,就可以退出去了
buf.append(new String(tmp, 0, i));
}
if (channelExec.isClosed()) {
//判斷連接關閉,這個是在把信息讀出來之后判斷的
res = channelExec.getExitStatus();
//這個是狀態碼,正常是0,如果運行命令出問題就不是0了;不同的數值代表不同的錯誤
if (res != 0)
log.error(format("Exit-status: %d", res));
break;
}
}
if (res != 0){
log.error(buf.toString());
channelExec.disconnect();
//操作完后channel連接關閉
return null;
}
channelExec.disconnect();
//操作完后channel連接關閉
return buf.toString();
}
private String download(String downloadFile) throws JSchException, SftpException, IOException {
if (!bConnect)
initConnection();
ChannelSftp channelSftp = (ChannelSftp) session.openChannel("sftp");
channelSftp.connect();
StringBuilder result = new StringBuilder();
String temp = "";
InputStream is = channelSftp.get(downloadFile);
byte[] buff = new byte[1024 * 2];
int read;
if (is != null) {
log.debug("Start to read input stream");
do {
read = is.read(buff, 0, buff.length);
if (read > 0) {
temp = new String(buff);
result.append(temp);
}
} while (read >= 0);
log.debug("input stream read done.");
}
channelSftp.disconnect();
return result.toString();
}
public synchronized String execOnly(String cmd) throws IOException, JSchException {
String result = exec(cmd);
close();
//在close()里邊把bconnect置為false,關閉此次連接。(每調用一次后,就關閉連接)
return result;
}
public String execAndDownload(String cmd) throws IOException, JSchException, SftpException {
String fileName = exec(cmd);
String fileData = download(fileName.replace("\n", ""));
close();
//ession連接關閉
return fileData;
}
private void close() {
session.disconnect();
bConnect = false;
}
}
session是跟遠程主機建立一個連接,JSch 在這個連接上建立一個通道專門執行命令,setCommand就是一個字節數組,存儲我要執行的命令,然后打開一個流,通過這個流將我要執行的命令送到遠程主機上執行,上圖代碼中的in里面是返回過來的數據。