需求说明
- 在一台Linux服务器(作为主服务器)上部署java代码,实现一台对多台(子)服务器的交互,完成文件传输和命令的操作(如 查询、进程的kill,java命令的操作等)
- 不可以远程连接使用root用户权限,各个连接的服务器需创建新用户(tester)去访问;
常规操作
- linux创建新用户–不赘述
- 网上sftp协议(实现文件下载 上传)和 ssh协议(实现)的代码大把的 这里提供两个(见下方)
踩的坑
- 主服务器ssh远程不到子服务器
- 遍历一个ip的字符串集合 List,连接了当前ip,进行的操作却是执行了上一个ip的数据;
- 远程代码执行 kill 命令操作 执行失败;
- 远程代码执行 java -jar 命令操作jar包,执行失败,且卡在执行java -jar 命令的代码一行 不再往下执行其他代码;
坑1 :主服务器ssh远程不到子服务器,远程到了 也执行不了命令
操作:
远程连接到子服务器:
方法1:需要输入用户密码ssh -p 端口号 用户名@IP地址
如 :ssh -p 22 tester@10.10.10.10
方法2:不需要二次输入密码sshpass -p 用户密码 ssh -P -o StrictHostKeyChecking=no -p 端口号 用户名@IP地址
如:sshpass -p a12345 ssh -P -o StrictHostKeyChecking=no -p 22 tester@10.10.10.10
解决:
在子服务器下主服务器ip添加至白名单即可:vi /etc/hosts.allow
在最后一行加入主服务器的ip:内容如下sshd:主服务器IP
如:sshd:10.10.10.10
远程到了代码也执行不了ssh操作的解决:
原因:用户权限不足,在子服务器添加用户权限
解决:在子服务器中执行如下命令
1.切换到root用户下,怎么切换就不用说了吧,不会的自己百度去.
2.添加sudo文件的写权限,命令是:chmod u+w /etc/sudoers
3.编辑sudoers文件vi /etc/sudoers
找到这行 root ALL=(ALL) ALL,在他下面添加xxx ALL=(ALL) ALL (这里的xxx是你的用户名)
ps:这里说下你可以sudoers添加下面四行中任意一条
youuser ALL=(ALL) ALL
%youuser ALL=(ALL) ALLtester ALL=(ALL) NOPASSWD: ALL
%youuser ALL=(ALL) NOPASSWD: ALL
第一行:允许用户youuser执行sudo命令(需要输入密码).
第二行:允许用户组youuser里面的用户执行sudo命令(需要输入密码).第三行:允许用户tester执行sudo命令,并且在执行的时候不输入密码.
第四行:允许用户组youuser里面的用户执行sudo命令,并且在执行的时候不输入密码.
4.撤销sudoers文件写权限,命令:chmod u-w /etc/sudoers
这样普通用户就可以使用sudo了
资源摘抄于
坑2 :遍历一个ip的字符串集合 List,连接了当前ip,进行的操作却是执行了上一个ip的数据;
解决:
SFTPUtils类中的getInstance()方法 实例化对象 ,连接下一个ip服务器后未重新创建,改为下方的即可; 每次连接都创建新的对象。(可再考虑优化);
//获取实例化对象
public static SFTPUtils getInstance(String host, int port, String username, String password) {
SFTPUtils instance = new SFTPUtils();//创建连接对象
sftp = instance.connect(host, port, username, password); //获取连接
return instance;
}
SSHUtils类同理 代码中已更改。
坑3 :远程代码执行 kill 命令操作 执行失败;
解决:
由于我远程连接的不是root用户,新创建的一个测试用户tester无root权限 需要使用sudo kill + 进程号
坑4: 远程代码执行 java -jar 命令操作jar包,执行失败,且卡在执行java -jar 命令的代码一行 不再往下执行其他代码;
解决:(其实最后也没有解决,只是找到了问题 跳过了问题)
使用ssh协议执行java -jar ,命令时发现 代码卡着不走了,也没报错,但是发现java命令确实已经运行了,最后一点一点找 发现是因为我们执行linux的命令时候往往需要获取命令执行的返回值,代码中命令执行后 ,把返回结果转化为IO流后返回 ,java -jar命令的运行就是在这里出了问题,如下两行代码:
InputStream stdout = new StreamGobbler(openSession.getStdout());
out = IOUtils.toString(stdout, StandardCharsets.UTF_8);
执行java -jar命令时候删除这两行代码运行 即可!(投机取巧,博主未真正解决问题)
代码如下:(仅供参考)
添加maven依赖
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.28</version>
</dependency>
<dependency>
<groupId>ch.ethz.ganymed</groupId>
<artifactId>ganymed-ssh2</artifactId>
<version>262</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.jcraft/jsch -->
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.55</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
sftp协议
import com.jcraft.jsch.*;
import com.jcraft.jsch.ChannelSftp.LsEntry;
import org.apache.logging.log4j.Logger;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Properties;
import java.util.Vector;
/**
* SFTP
*/
public class SFTPUtils {
private static final Logger LOG = org.apache.logging.log4j.LogManager.getLogger(SFTPUtils.class);
private static ChannelSftp sftp;
private SFTPUtils() {
}
//获取实例化对象
public static SFTPUtils getInstance(String host, int port, String username, String password) {
if (instance == null) {
if (instance == null) {
instance = new SFTPUtils();
sftp = instance.connect(host, port, username, password); //获取连接
}
}
return instance;
}
/**
* 连接sftp服务器
*
* @param host 主机
* @param port 端口
* @param username 用户名
* @param password 密码
* @return
*/
public ChannelSftp connect(String host, int port, String username, String password) {
ChannelSftp sftp = null;
try {
JSch jsch = new JSch();
jsch.getSession(username, host, port);
Session sshSession = jsch.getSession(username, host, port);
sshSession.setPassword(password);
Properties sshConfig = new Properties();
sshConfig.put("StrictHostKeyChecking", "no");
sshSession.setConfig(sshConfig);
sshSession.connect();
LOG.info("SFTP Session connected.");
Channel channel = sshSession.openChannel("sftp");
channel.connect();
sftp = (ChannelSftp) channel;
LOG.info("Connected to " + host);
} catch (Exception e) {
LOG.error(e.getMessage());
}
return sftp;
}
/**
* 上传文件
*
* @param directory 上传的目录
* @param uploadFile 要上传的文件
*/
public boolean upload(String directory, String uploadFile) {
try {
sftp.cd(directory);
File file = new File(uploadFile);
FileInputStream fileInputStream = new FileInputStream(file);
sftp.put(fileInputStream, file.getName());
fileInputStream.close();
return true;
} catch (Exception e) {
LOG.error(e.getMessage());
return false;
}
}
/**
* 下载文件
*
* @param directory 下载目录
* @param downloadFile 下载的文件
* @param saveFile 存在本地的路径
*/
public File download(String directory, String downloadFile, String saveFile) {
try {
sftp.cd(directory);
File file = new File(saveFile);
FileOutputStream fileOutputStream = new FileOutputStream(file);
sftp.get(downloadFile, fileOutputStream);
fileOutputStream.close();
return file;
} catch (Exception e) {
LOG.error(e.getMessage());
return null;
}
}
/**
* 下载文件
*
* @param downloadFilePath 下载的文件完整目录
* @param saveFile 存在本地的路径
*/
public File download(String downloadFilePath, String saveFile) {
try {
int i = downloadFilePath.lastIndexOf('/');
if (i == -1)
return null;
sftp.cd(downloadFilePath.substring(0, i));
File file = new File(saveFile);
FileOutputStream fileOutputStream = new FileOutputStream(file);
sftp.get(downloadFilePath.substring(i + 1), fileOutputStream);
fileOutputStream.close();
return file;
} catch (Exception e) {
LOG.error(e.getMessage());
return null;
}
}
/**
* 删除文件
*
* @param directory 要删除文件所在目录
* @param deleteFile 要删除的文件
*/
public void delete(String directory, String deleteFile) {
try {
sftp.cd(directory);
sftp.rm(deleteFile);
} catch (Exception e) {
LOG.error(e.getMessage());
}
}
/**
* 断开连接
*/
public void disconnect() {
try {
sftp.getSession().disconnect();
} catch (JSchException e) {
LOG.error(e.getMessage());
}
sftp.quit();
sftp.disconnect();
}
/**
* 列出目录下的文件
*
* @param directory 要列出的目录
* @throws SftpException
*/
public Vector<LsEntry> listFiles(String directory) throws SftpException {
return sftp.ls(directory);
}
}
SSH协议
import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.Session;
import ch.ethz.ssh2.StreamGobbler;
import org.apache.commons.io.IOUtils;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
public class SSHUtils {
private static Connection conn = null;
// private static final String baseDir = "/work/Apk_Release/KeKeUserCenter";
public static Connection getSSHConnection(String ip, int port, String user, String password) {
try {
conn = new Connection(ip, port);
conn.connect();
synchronized (conn){
if(!conn.isAuthenticationComplete()) {
if (conn.authenticateWithPassword(user, password)) {
System.out.println("连接" + ip + ",成功");
}
}
}
} catch (IOException e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
return conn;
}
public static boolean closeSSHConnection() {
if (conn != null) {
conn.close();
return true;
}
return false;
}
public static void exeJavaCommand(String ip, int port, String user, String password, String command){
Connection conn;
try {
//连接服务器
conn = getSSHConnection(ip, port, user, password);
Session openSession = conn.openSession();
//执行命令
openSession.execCommand(command);
// InputStream stdout = new StreamGobbler(openSession.getStdout());
// out = IOUtils.toString(stdout, StandardCharsets.UTF_8);
} catch (IOException e) {
e.printStackTrace(System.err);
} finally {
if (closeSSHConnection()) {
conn = null;
System.out.println("断开连接成功");
}else {
System.out.println("断开连接失败");
}
}
}
public static String exeCommand(String ip, int port, String user, String password, String command){
Connection conn;
String out = null;
try {
//连接服务器
conn = getSSHConnection(ip, port, user, password);
Session openSession = conn.openSession();
//执行命令
openSession.execCommand(command);
InputStream stdout = new StreamGobbler(openSession.getStdout());
out = IOUtils.toString(stdout, StandardCharsets.UTF_8);
} catch (IOException e) {
e.printStackTrace(System.err);
} finally {
if (closeSSHConnection()){
conn = null;
System.out.println("断开连接成功");
}else {
System.out.println("断开连接失败");
}
}
return out;
}
}