首先确保服务器已经安装JSch,这是一个可以使用Java实现SSH连接的类库。客户端已经安装了expect组件。
接下来需要实现以下几个步骤:
-
通过Sshconnect.sh脚本启动客户端的SSH服务(如果还没有启动)
-
使用JSch库建立反向隧道连接到客户端的SSH服务
-
调用客户端资源,比如摄像头
下面是代码示例:
import com.jcraft.jsch.*;
public class SshReverseTunnel {
public static void main(String[] args) {
String host = "client_host"; // 客户端主机名或 IP
int port = 22; // 客户端 SSH 服务端口号
String user = "client_user"; // 客户端 SSH 用户名
String password = "******"; // 客户端 SSH 密码
try {
// 启动客户端的 SSH 服务
Runtime.getRuntime().exec("/path/to/Sshconnect.sh");
JSch jsch = new JSch();
Session session = jsch.getSession(user, host, port);
session.setPassword(password);
// 设置配置项
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
config.put("Compression", "yes");
config.put("ConnectionAttempts", "2");
session.setConfig(config);
session.connect();
// 建立反向隧道
int tunnelPort = 12345; // 当前服务器上监听的端口号
int remotePort = 22; // 客户端上用于监听的端口号
String remoteServer = "localhost"; // 客户端上监听地址,本例是客户端本地
session.setPortForwardingR(tunnelPort, remoteServer, remotePort);
// 调用客户端资源,比如摄像头
// 断开连接
session.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
}
客户端要定时去检查这个端口和服务是否启动。代码如下:
/**
* 定时获取ssh通道端口,并建立、关闭 连接
*/
@Override
public void checkSport() throws Exception {
if (Constant.isEntered) {
FsmsRsp<SshQryRspVo> resp = RemoteServerUtil.form(ssh_url + "/" + Constant.localInfoBus.getBusId(), new HashMap(), new FsmsRsp<SshQryRspVo>() {
}.getClass());
SshQryRspVo sshQryRspVo = resp.getData();
int sport = sshQryRspVo.getSport();
if (sport == 0) {
log.info("从服务器取得信息,将关闭本端口"+sshQryRspVo.getIp()+"/"+sshQryRspVo.getPort());
Constant.sshSport = 0;
//关闭ssh
Process ps = Runtime.getRuntime().exec(localShellSshScript + " close x x x x x");
ps.waitFor();
} else {
log.info("从服务器取得信息,将创建SSH通道");
Constant.sshSport = sport;
String ip = sshQryRspVo.getIp();
int port = sshQryRspVo.getPort();
String username = sshQryRspVo.getUsername();
String passwrod = sshQryRspVo.getPassword();
log.info("创建SSH通道命令如下:\r\n"+localShellSshScript + " open " + ip + " " + port + " " + username + " " + passwrod + " " + sport);
//打开ssh
Process ps = Runtime.getRuntime().exec(localShellSshScript + " open " + ip + " " + port + " " + username + " " + passwrod + " " + sport);
ps.waitFor();
}
}
}
其中执行的脚本.sh是这样的,上文当中的变量localShellSshScript=sshconnect.sh,放在根目录下。
#!/bin/bash
flag="$1"
ip="$2"
port="$3"
username="$4"
password="$5"
sport="$6"
#echo ${flag} >> /data/ec/scripts/xxx.log
#echo ${ip} >> /data/ec/scripts/xxx.log
#echo ${port} >> /data/ec/scripts/xxx.log
#echo ${username} >> /data/ec/scripts/xxx.log
#echo ${password} >> /data/ec/scripts/xxx.log
#echo ${sport} >> /data/ec/scripts/xxx.log
if [ "${flag}" = "open" ]; then
#echo '11111111111111111111' >> /data/ec/scripts/xxx.log
count=`ps -aux | grep ':localhost:7001' | grep -v grep | wc -l`
if [ "${count}" -eq "0" ];then
#echo '222222222222' >> /data/ec/scripts/xxx.log
/usr/bin/expect << EOF
set time 30
spawn ssh -p ${port} -fCNR ${sport}:localhost:7001 ${username}@${ip}
expect {
"*yes/no*" {send "yes\r"; exp_continue }
"*password:" { send "${password}\r" }
}
expect eof
EOF
fi
elif [ "${flag}" = "close" ]; then
#echo '333333333333' >> /data/ec/scripts/xxx.log
kill -9 `ps -aux | grep ':localhost:7001' | grep -v grep | awk '{print $2}'`
fi
#echo '444444444444' >> /data/ec/scripts/xxx.log