ssslinppp

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  274 随笔 :: 1 文章 :: 48 评论 :: 101万 阅读
< 2025年2月 >
26 27 28 29 30 31 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 1
2 3 4 5 6 7 8

如果大家熟悉Linux的话,一定对ssh,sftp,scp等命令非常熟悉,ssh是一个安全协议,用来在不同系统或者服务器之间进行安全连接,SSH 在连接和传送的过程中会加密所有的数据。
但是SSH一般是基于客户端的或者Linux命令行的,比如客户端的工具:OpenSSH,putty,SSH Tectia;
在linux上大家可以通过ssh username@host连接到所要想连接的主机。
但是如果在J2EE中,如何实现SSH呢?进而可以实现SCP,SFTP的功能呢?下面介绍的JSCH就可以实现下边的功能。
JSCH是一个纯粹的用java实现SSH功能的java  library;

maven依赖
<dependency>
    <groupId>com.jcraft</groupId>
    <artifactId>jsch</artifactId>
    <version>0.1.44</version>
</dependency>

关键类介绍

  • JSch:  作为中心配置点,以及Session的工厂;
 This class serves as a central configuration point, and as a factory for Session objects configured with these settings.
  1. Use getSession to start a new Session.
  2. Use one of the addIdentity methods for public-key authentication.
  3. Use setKnownHosts to enable checking of host keys.
  4. See setConfig for a list of configuration options.

  • Session:表示到远程SSH服务器的一个连接,可以包含多个Channels;
 A Session represents a connection to a SSH server.One session can contain multiple Channels of various types
A session is opened with connect() and closed with disconnect().

  • Channel :  与Session相关联的通道,有多种不同类型;
The abstract base class for the different types of channel which may be associated with a Session.
  1. shell - ChannelShell :A channel connected to a remote shell (本次使用的Channel)
  2. exec - ChannelExec :A channel connected to a remotely executing program
  3. direct-tcpip - ChannelDirectTCPIP: A Channel which allows forwarding a pair of local streams to/from a TCP-connection to a server on the remote side
  4. sftp - ChannelSftp :A Channel connected to an sftp server (as a subsystem of the ssh server).
  5. subsystem - ChannelSubsystem :A channel connected to a subsystem of the server process

使用步骤

使用Jsch进行SSH连接的具体步骤如下:
  • 步骤1: 使用Jsch获取Session: jsch.getSession()
  • 步骤2: 设置Session的password和属性等: setPassword()/setConfig();
  • 步骤3: 设置SocketFactory(可以不进行设置,使用默认的TCP socket);
  • 步骤4: 打开Session连接:connect();
  • 步骤5: 打开并连接Channel:openChannel()/connect();
  • 步骤6: 获取Channel的inputStream和outputStream,执行指定cmd或其他;
  1.   getInputStream():  All data arriving in SSH_MSG_CHANNEL_DATA messages from the remote side can be read from this stream
  2.   getOutputStream():  All data written to this stream will be sent in SSH_MSG_CHANNEL_DATA messages to the remote side.
  • 步骤7: 关闭各种资源:输入输出流/Session/Channel等;

创建Session,并打开Session连接

步骤1~步骤4:程序如下

使用SSH协议,连接到Linux,执行指定命令,并获取结果

步骤5~步骤6:程序如下

执行Shell命令,并获取执行结果

测试程序





完整程序

JSCHUtil.java

package com.sssppp.Communication;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Properties;

import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SocketFactory;

/**
 * 相关链接: JSCH api:http://epaul.github.io/jsch-documentation/javadoc/ Example:
 * http://www.jcraft.com/jsch/examples/
 * 
 * @author xxxx
 * 
 */
public class JSCHUtil {
  private static JSch jsch = new JSch();

  /**
   * 创建Session,并打开Session连接
   * 
   * @param dstIp
   * @param dstPort
   * @param localIp
   * @param localPort
   * @param userName
   * @param password
   * @param timeOut
   * @return
   * @throws JSchException
   */
  public static Session createSession(String dstIp, int dstPort,
      final String localIp, final int localPort, String userName,
      String password, final int timeOut) throws JSchException {
    //jsch.setKnownHosts("/home/foo/.ssh/known_hosts");
    
    // A Session represents a connection to a SSH server
    Session session = jsch.getSession(userName, dstIp, dstPort);
    session.setPassword(password);
    
    Properties sshConfig = new Properties();
    sshConfig.put("StrictHostKeyChecking", "no");//To skip host-key check
    session.setConfig(sshConfig);

    // this socket factory is used to create a socket to the target host,
    // and also create the streams of this socket used by us
    session.setSocketFactory(new SocketFactory() {
      @Override
      public OutputStream getOutputStream(Socket socket)
          throws IOException {
        return socket.getOutputStream();
      }

      @Override
      public InputStream getInputStream(Socket socket) throws IOException {
        return socket.getInputStream();
      }

      @Override
      public Socket createSocket(String host, int port)
          throws IOException, UnknownHostException {
        Socket socket = new Socket();
        if (localIp != null) {
          socket.bind(new InetSocketAddress(InetAddress
              .getByName(localIp), localPort));
        }
        socket.connect(
            new InetSocketAddress(InetAddress.getByName(host), port),
            timeOut);
        return socket;
      }
    });

    session.connect(timeOut);
    return session;
  }
}


SSHCommUtil.java

package com.sssppp.Communication;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;

public class SSHCommUtil {

  /**
   * 测试程序
   * @param args
   */
  public static void main(String[] args) {
    String ip = "10.180.137.241";
    int port = 22;
    String localIp = null;
    int localPort = 0;
    int timeOut = 3000;
    String userName = "xxx";
    String password = "xxx";
    String[] cmds = new String[] { "ifconfig | grep eth0\n",
        "cat /etc/redhat-release\n" };
    String[] result = null;
    try {
      result = execShellCmdBySSH(ip, port, localIp, localPort, timeOut,
          userName, password, cmds);
    } catch (Exception e) {
      e.printStackTrace();
    }

    if (result != null) {
      for (String string : result) {
        System.out.println(string);
        System.out.println("-------------------");
      }
    }

  }

  /**
   * 使用SSH协议,连接到Linux Shell,执行脚本命令,并获取结果
   * 
   * @param dstIp
   * @param dstport
   *            default :22
   * @param localIp
   * @param localPort
   * @param timeOut
   * @param userName
   * @param password
   * @param cmds
   * @return
   * @throws Exception
   */
  public static String[] execShellCmdBySSH(String dstIp, int dstport,
      String localIp, int localPort, int timeOut, String userName,
      String password, String... cmds) throws Exception {
    Session session = null;
    Channel channel = null;
    InputStream is = null;
    OutputStream os = null;
    try {
      session = JSCHUtil.createSession(dstIp, dstport, localIp,
          localPort, userName, password, timeOut);
      channel = session.openChannel("shell");
    
      // Enable agent-forwarding.
      // ((ChannelShell)channel).setAgentForwarding(true);

      // Choose the pty-type "vt102".
      // ((ChannelShell)channel).setPtyType("vt102");

      // Set environment variable "LANG" as "ja_JP.eucJP".
      // ((ChannelShell)channel).setEnv("LANG", "ja_JP.eucJP");

      channel.connect();
      is = channel.getInputStream();
      os = channel.getOutputStream();
      String[] result = new String[cmds.length];
      for (int i = 0; i < cmds.length; i++) {
        result[i] = sendCommand(is, os, cmds[i]);
      }
      return result;
    } catch (JSchException e) {
      if (e.getMessage().contains("Auth fail")) {
        throw new Exception("Auth error");
      } else {
        throw new Exception("Connect error");
      }
    } catch (Exception e) {
      throw e;
    } finally {
      try {
        is.close();
      } catch (IOException e) {
      }
      try {
        os.close();
      } catch (IOException e) {
      }

      channel.disconnect();
      session.disconnect();
    }
  }
  
  /**
   * 执行Shell命令,并获取执行结果
   * 
   * @param is
   * @param os
   * @param cmd
   * @return
   * @throws IOException
   */
  private static String sendCommand(InputStream is, OutputStream os,
      String cmd) throws IOException {
    os.write(cmd.getBytes());
    os.flush();

    StringBuffer sb = new StringBuffer();
    int beat = 0;
    while (true) {
      if (beat > 3) {
        break;
      }

      if (is.available() > 0) {
        byte[] b = new byte[is.available()];
        is.read(b);
        sb.append(new String(b));
        beat = 0;
      } else {
        if (sb.length() > 0) {
          beat++;
        }

        try {
          Thread.sleep(sb.toString().trim().length() == 0 ? 1000
              : 300);
        } catch (InterruptedException e) {
        }
      }
    }
    return sb.toString();
  }
}








posted on   ssslinppp  阅读(8519)  评论(0编辑  收藏  举报
编辑推荐:
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
阅读排行:
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 本地部署DeepSeek后,没有好看的交互界面怎么行!
· 趁着过年的时候手搓了一个低代码框架
· 推荐一个DeepSeek 大模型的免费 API 项目!兼容OpenAI接口!
· 用 C# 插值字符串处理器写一个 sscanf
点击右上角即可分享
微信分享提示