為什么需要遠程登錄執行?
? 我們有時候通過業務代碼會關聯一些東西,那么在這個時候做完操作后有可能需要去其他服務器上執行一些命令,例如我們更換了什么文件,然后需要重啟另一個服務,那么這個時候就需要我們去遠程執行命令了。
如何遠程執行命令?
? 有兩種方式,我們可以使用jsch和ganymed來進行實現,兩個包都是對SSH2的封裝,能夠幫助我們遠程連接服務器,并且執行命令。
jsch
? 引入依賴
<!-- https://mvnrepository.com/artifact/com.jcraft/jsch -->
<dependency><groupId>com.jcraft</groupId><artifactId>jsch</artifactId><version>0.1.55</version>
</dependency>
遠程執行命令
? 首先新建工具類
package com.test.boot.utils;import com.jcraft.jsch.*;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;/*** @Author BigKang* @Date 2020/12/14 5:45 下午* @Motto 仰天大笑擼碼去, 我輩豈是蓬蒿人* @Summarize Jsch工具類*/
@Slf4j
@Getter
@Setter
public class JschUtil {/*** 主機IP*/private String host;/*** 默認端口*/private int port;/*** 用戶名*/private String username;/*** 密碼*/private String password;/*** 設置編碼格式*/private String charset;/*** JSch對象*/private JSch jsch;/*** 會話Session*/private Session session;/*** 默認端口號*/private static final Integer DEFAULT_PORT = 22;/*** 默認編碼*/private static final String DEFAULT_CHARSET = "UTF-8";/*** 構造方法*/public JschUtil() {}/*** 構造方法** @param host HostIp地址* @param port 端口號* @param username 用戶名* @param password 密碼* @param charset 編碼*/public JschUtil(String host, int port, String username, String password, String charset) {this.host = host;this.port = port;this.username = username;this.password = password;this.charset = charset;}/*** 構造方法** @param host HostIp地址* @param port 端口號* @param username 用戶名* @param password 密碼*/public JschUtil(String host, int port, String username, String password) {this.host = host;this.port = port;this.username = username;this.password = password;this.charset = DEFAULT_CHARSET;}/*** 構造方法** @param host HostIp地址* @param username 用戶名* @param password 密碼*/public JschUtil(String host, String username, String password) {this.host = host;this.port = DEFAULT_PORT;this.username = username;this.password = password;this.charset = DEFAULT_CHARSET;}/*** 連接到指定的IP** @throws JSchException*/private void connect() {// 連接到SSH服務器try {jsch = new JSch();session = jsch.getSession(username, host, port);session.setPassword(password);java.util.Properties config = new java.util.Properties();config.put("StrictHostKeyChecking", "no");session.setConfig(config);session.setTimeout(10000);session.connect();log.debug("SSH2 Client:{} Success", host);} catch (Exception e) {throw new RuntimeException("連接SSH失敗!");}}/*** 關閉連接*/public void close() {// 關閉Session會話,SFTP使用同一個Session會隨之關閉session.disconnect();}/*** 執行Command命令* @param command 命令字符串* @return*/public String execCommand(String command) {connect();ChannelExec exec = null;InputStream in = null;BufferedReader reader = null;StringBuffer result = new StringBuffer();try {exec = (ChannelExec) session.openChannel("exec");exec.setCommand(command);exec.connect();in = exec.getInputStream();reader = new BufferedReader(new InputStreamReader(in));String tmpStr = "";while ((tmpStr = reader.readLine()) != null) {result.append(new String(tmpStr.getBytes("gbk"), "UTF-8")).append("\n");}} catch (IOException | JSchException ioException) {ioException.printStackTrace();}finally {try {reader.close();in.close();exec.disconnect();close();}catch (Exception e){log.error("Close SSH Command Failure!");}}return result.toString();}}
? 然后調用工具類即可
JschUtil jschUtil = new JschUtil("192.168.1.11",22,"root","root123");String s = jschUtil.execCommand("cd && ls");System.out.println(s);
Java方式打造SSH客戶端
import com.jcraft.jsch.*;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Scanner;
import java.util.concurrent.atomic.AtomicBoolean;public class Test {private static Object object = new Object();public static void main(String[] args) throws IOException, JSchException, InterruptedException {java.util.Properties config = new java.util.Properties();config.put("StrictHostKeyChecking", "no");JSch jsch = new JSch();// 設置用戶名,地址,端口號Session session = jsch.getSession("bigkang", "39.108.158.33", 22);// 設置密碼session.setPassword("Kangbaba666");session.setConfig(config);session.connect();// 設置管道類型為shellChannelShell channel = (ChannelShell) session.openChannel("shell");channel.setPty(true);channel.connect();// 輸入輸出流InputStream inputStream = channel.getInputStream();OutputStream outputStream = channel.getOutputStream();Scanner scanner = new Scanner(System.in);scanner.useDelimiter("\n");AtomicBoolean flag = new AtomicBoolean(true);new Thread(() -> {//如果沒有數據來,線程會一直阻塞在這個地方等待數據。try {byte[] buffer = new byte[1024];int i = 0;//如果沒有數據來,線程會一直阻塞在這個地方等待數據。while ((i = inputStream.read(buffer)) != -1) {String str = new String(Arrays.copyOfRange(buffer, 0, i), "UTF-8");System.out.print(str);}System.out.println("連接斷開");flag.set(false);inputStream.close();outputStream.close();channel.disconnect();session.disconnect();} catch (IOException e) {e.printStackTrace();}}, "ReadThread").start();// 循環向輸入流寫入while (flag.get()) {String next = scanner.next();// 命令加上\r表示回車next += "\r";if(channel.getExitStatus() == -1) {// 寫入outputStream.write(next.getBytes(), 0, next.length());outputStream.flush();}else {System.out.println("退出登錄");}}}
ganymed
本地執行Shell
public String execShell(String command) throws IOException {Process process = null;BufferedReader br = null;String line = null;String[] cmd;String osName = System.getProperty("os.name");if (osName.startsWith("Windows")) {cmd = new String[3];if (osName.equals("Windows 95")) {cmd[0] = "command.com";} else {cmd[0] = "cmd.exe";}cmd[1] = "/C";cmd[2] = command;} else if (osName.equals("Linux")) {cmd = new String[3];cmd[0] = "/bin/sh";cmd[1] = "-c";cmd[2] = command;} else if (osName.contains("Mac")) {cmd = new String[3];cmd[0] = "/bin/sh";cmd[1] = "-c";cmd[2] = command;} else {cmd = new String[1];cmd[0] = command;}process = Runtime.getRuntime().exec(cmd);br = new BufferedReader(new InputStreamReader(process.getInputStream(), Charset.forName("GBK")));StringBuilder sb = new StringBuilder();while ((line = br.readLine()) != null) {sb.append(line + "\n");}return sb.toString();}
The end.