Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ssh/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Java的SSH连接_Java_Ssh_Ssh Keys_J2ssh - Fatal编程技术网

使用Java的SSH连接

使用Java的SSH连接,java,ssh,ssh-keys,j2ssh,Java,Ssh,Ssh Keys,J2ssh,我正试图通过Java代码建立SSH连接,但遇到以下异常。。我通过Putty/Winscp工具测试了我的连接,效果很好。问题在于我的Java代码 SEVERE: The Transport Protocol thread failed java.io.IOException: The socket is EOF at com.sshtools.j2ssh.transport.TransportProtocolInputStream.readBufferedData(Unknown Sour

我正试图通过Java代码建立SSH连接,但遇到以下异常。。我通过Putty/Winscp工具测试了我的连接,效果很好。问题在于我的Java代码

SEVERE: The Transport Protocol thread failed
java.io.IOException: The socket is EOF
    at com.sshtools.j2ssh.transport.TransportProtocolInputStream.readBufferedData(Unknown Source)
    at com.sshtools.j2ssh.transport.TransportProtocolInputStream.readMessage(Unknown Source)
    at com.sshtools.j2ssh.transport.TransportProtocolCommon.readMessage(Unknown Source)
    at com.sshtools.j2ssh.transport.kex.DhGroup1Sha1.performClientExchange(Unknown Source)
    at com.sshtools.j2ssh.transport.TransportProtocolClient.performKeyExchange(Unknown Source)
    at com.sshtools.j2ssh.transport.TransportProtocolCommon.beginKeyExchange(Unknown Source)
    at com.sshtools.j2ssh.transport.TransportProtocolCommon.onMsgKexInit(Unknown Source)
    at com.sshtools.j2ssh.transport.TransportProtocolCommon.startBinaryPacketProtocol(Unknown Source)
    at com.sshtools.j2ssh.transport.TransportProtocolCommon.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
下面是我建立连接的一段Java代码

public class MySSHClient {

  static SshClient ssh = null;
  static SshConnectionProperties properties = null;
  SessionChannelClient session = null;

  private static void MySSHClient(String hostName, String userName, String passwd )
  {

    try
    {
      // Make a client connection
      ssh = new SshClient();
      properties = new SshConnectionProperties();
      properties.setHost("192.168.1.175");

      // Connect to the host
      ssh.connect(properties, new IgnoreHostKeyVerification());

      // Create a password authentication instance
      PasswordAuthenticationClient pwd = new PasswordAuthenticationClient();

      pwd.setUsername("root");
      pwd.setPassword("123456");

      // Try the authentication
      int result = ssh.authenticate(pwd);

      // Evaluate the result
      if (result==AuthenticationProtocolState.COMPLETE) {

        System.out.println("Connection Authenticated");
      }
    }
    catch(Exception e)
    {
      System.out.println("Exception : " + e.getMessage());
    }

  }//end of method.


  public String execCmd(String cmd)
  {
    String theOutput = "";
    try
    {
      // The connection is authenticated we can now do some real work!
      session = ssh.openSessionChannel();

      if ( session.executeCommand(cmd) )
      {
        IOStreamConnector output = new IOStreamConnector();
        java.io.ByteArrayOutputStream bos =  new
        java.io.ByteArrayOutputStream();
        output.connect(session.getInputStream(), bos );
        session.getState().waitForState(ChannelState.CHANNEL_CLOSED);
        theOutput = bos.toString();
      }
      //else
      //throw Exception("Failed to execute command : " + cmd);
      //System.out.println("Failed to execute command : " + cmd);
    }
    catch(Exception e)
    {
      System.out.println("Exception : " + e.getMessage());
    }

    return theOutput;
  }

  public static void main(String[] args){
      MySSHClient(null, null, null);
    }
当j2ssh.jar文件与SFTP服务器的当前SSH版本不兼容时,会发生此错误(“传输协议线程失败。java.io.IOException:套接字为EOF”)

您可以尝试从中使用Java安全通道(JSch)


礼貌:

以下示例代码可能对您有所帮助

import java.io.InputStream;
import org.apache.commons.io.IOUtils;


import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;


public class SSHClient {

    /**
     * Constant EXCUTE_CHANNEL
     */
    public static final String EXCUTE_CHANNEL = "exec";

    /**
     * Constant STRICT_KEY_CHECKING
     */
    public static final String STRICT_KEY_CHECKING = "StrictHostKeyChecking";


    /** Name/ip of the remote machine/device **/ 
    private String host;
    private String userName;
    private String password;

    /**
     * This method used to initilze user and host
     * 
     * @param userName
     * @param password
     * @param host
     */
    public SSHClient(String userName,String password, String host) {
        super();
        this.userName = userName;
        this.password = password;
        this.host = host;
    }

    /**
     * This method used to execute commands remotly by using SSHV2
     * 
     * @param host
     * @param username
     * @param password
     * @param command
     * @return
     */
    public String executeCommand(String command) { 
        StringBuilder log = new StringBuilder();
        String response = null;
        Channel channel = null;
        Session session = null;

        try {
            JSch jsch = new JSch();
            JSch.setConfig(STRICT_KEY_CHECKING, Constants.NO);

            session = jsch.getSession(userName, host, 22);


            // If two machines have SSH passwordless logins setup, the following
            // line is not needed:
            session.setPassword(password);
            session.connect();

            channel = session.openChannel(EXCUTE_CHANNEL);
            ((ChannelExec) channel).setCommand(command);

            // channel.setInputStream(System.in);
            channel.setInputStream(null);

            ((ChannelExec) channel).setErrStream(System.err);

            InputStream in = channel.getInputStream();

            channel.connect();

            response = IOUtils.toString(in);

        } catch (Exception ex) {
                //handle exception
        } finally {
            try {
                if (session != null) {
                    session.disconnect();
                }
            } catch (Exception ex) {
                //handle exception
            }
            try {
                if (channel != null) {
                    channel.disconnect();
                }
            } catch (Exception ex) {
                //handle exception
            }

        }
        System.ou.println( "Response received :"+  response));
        return response;
    }
}
动机 我在调查问题
java.io.IOException中的错误时偶然发现了这个问题和答案:套接字是EOF
。因为在我的情况下,不可能立即将代码更改为使用其他SSH java库,而且@a3.14Infinity所述的解释对我来说不够详细,我想补充一下我的观点

IOException:套接字是EOF-为什么? 因为这个异常不是很有帮助,我首先尝试查看网络上发生了什么,但没有结果。因此我配置了
sshd\u config
(OpenSSH 6.9)登录到
DEBUG3
级别,并在我的测试机器的
/var/log/auth.log
文件中得到答案。它在尝试与SSH客户端(Java SSH库)协商密钥交换算法时声明了一个致命错误

由于SSH服务器和客户端无法就相互密钥交换算法达成一致,OpenSSH服务器终止与客户端的连接。因此,Java SSH库代码引发异常

但为什么会这样呢?
sshtools.j2ssh
()库代码非常陈旧且已停止使用。从(2014年10月发布)开始,默认密码和MAC已被修改,以删除不安全的算法,其中包括
河豚cbc
密码。和(2015年6月发布)默认情况下,禁用对1024位
diffie-hellman-group1-sha1
密钥交换的支持

当您仍然使用史前SSH工具
j2ssh
库时(上帝禁止)连接到较新的OpenSSH服务器时,将出现所述错误。库代码仅向OpenSSH服务器提供默认不支持的
diffie-hellman-group1-sha1
密钥交换算法。因此,无法建立安全连接

无法更改代码? 如果无法立即移动到另一个Java SSH库(我的情况),则可以在OpenSSH的服务器配置文件
sshd\u config
中重新启用禁用的
diffie-hellman-group1-sha1
密钥交换算法

Ciphers aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com,chacha20-poly1305@openssh.com,blowfish-cbc

KexAlgorithms diffie-hellman-group1-sha1,diffie-hellman-group-exchange-sha1,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha1
但是让我澄清一下。默认情况下,
diffie-hellman-group1-sha1
密钥交换算法以及
blowfish cbc
密码是关闭的,因为它们不安全。在替换这个过时的Java SSH库之前,重新启用它们应该只是一种临时措施

最后,我想指出,在其他答案中建议的java安全通道(JSCH)库已经停止。因此,您可能需要考虑或甚至替代。

< P> <强>编辑:我错了,java安全通道库是活的(JSCH 0.1.54在2016-0903发布),当然值得您考虑。 增编:移徙
为了尽量减少
sshtools.j2ssh
()库的迁移工作,我查看了来自(版本1.7.1)的商业版遗留SSH客户端库。这样就可以保留现有的库集成代码,而对库API和异常处理只做一些小的更改。因此,如果您不想从头开始,那么咬紧牙关并坚持使用SSHTOOLS可能是您最好的选择。最后,为了评估迁移工作,我首先将库替换为SSHTOOLS的open source库的API几乎与其最新的商业版本(1.7.1版)相同。

以下是从一些google源代码重用的工作代码-

import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.StreamGobbler;
连接连接=新连接(服务器);
连接();
布尔值isAuthenticated=conn.authenticateWithPassword(用户id,密码);
System.out.println(“服务器-”+server+“已验证?”+isAuthenticated);
如果(isAuthenticated==false)
抛出新IOException(“身份验证失败”);
ch.ethz.ssh2.Session sess=conn.openSession();
字符串new_commands=“”;
对于(int i=0;i
老实说,请尝试使用,异常和发布的代码似乎不匹配,而且未使用
execCmd
。linux主机上的
ssh
版本是什么[root@centos-test ssh]#ssh-v localhost OpenSSH_5.3p1,OpenSSL 1.0.1e-fips 2013年2月11日调试1:读取配置数据/etc/ssh/ssh_配置调试1:应用
Connection conn = new Connection(server);
conn.connect();
boolean isAuthenticated = conn.authenticateWithPassword(user_id, password);

System.out.println("Is server - " + server + " Authenticated? " + isAuthenticated);

if (isAuthenticated == false)
    throw new IOException("Authentication failed.");

ch.ethz.ssh2.Session sess = conn.openSession();
String new_commands = "";

for (int i = 0; i < commands.size(); i++) {
    new_commands = new_commands + commands.get(i) + "\n";
}

System.out.println("The command executed is: " + new_commands);

sess.requestDumbPTY();
sess.execCommand(new_commands);
InputStream stdout = new StreamGobbler(sess.getStdout());
BufferedReader br = new BufferedReader(new InputStreamReader(stdout));
InputStream errStrm = new StreamGobbler(sess.getStderr());
BufferedReader stderrRdr = new BufferedReader(new InputStreamReader(errStrm));
sess.getStdin().write("EXIT\n".getBytes());

System.out.println("the output of the command is");

while (true) {
    String line_out = br.readLine();
    if (line_out == null) {
        break;
    } else {
        System.out.println(line_out);
        output_logs.add(line_out);
    }
}

while (true) {
    String line_error = stderrRdr.readLine();
    if (line_error == null) {
        break;
    } else {
        System.out.println(line_error);
        output_logs.add(line_error);
    }
}

output_logs.add("Exit Code:" + sess.getExitStatus());
System.out.println("ExitCode: " + sess.getExitSignal());

sess.close();
conn.close();