【问题标题】:Java SSH Tools: SftpClient error: The remote computer disconnected: Protocol error: packet too long: 65580Java SSH 工具:SftpClient 错误:远程计算机已断开连接:协议错误:数据包太长:65580
【发布时间】:2015-08-24 01:24:26
【问题描述】:

我在尝试执行时收到“INFO:远程计算机已断开连接:协议错误:数据包太长:65580”错误:

sUpload("server.host.com", "username", "/home/localuser/.ssh/id_rsa", "filename", "");

文件不会传输到 SFTP 服务器(在另一端仅创建零字节)。当通过 Unix shell 手动 SFTP 时,一切正常。我在网上看到它可能是 SftpClient 中的 BLOCK_SIZE 的问题,但首先我找不到改变大小的设置方法,其次,默认值似乎是 65535,这完全不能解释错误中的 65580 值消息。

有什么想法吗?

我有以下使用 Java Ssh 工具 (j2ssh-core-0.2.9.jar) 的实用方法:

private static void sUpload(String ftpServer, String user, String password,
String localFile, String remoteFile) throws IOException {
    String methodName = "sUpload: ";
    System.out.println(" START ftpServer="+ftpServer+" user="+user+" password="+password);

    int result = 0;
    System.out.println("ftpServer " + ftpServer);
    System.out.println("user  " + user);
    System.out.println("password  " + password);
    System.out.println("localFile " + localFile);
    System.out.println("remoteFile    " + remoteFile);

    SshClient ssh = new SshClient();

    ssh.connect(ftpServer);

    System.out.println("Server Connected  ");
    if (password.contains("\\") || password.contains("/")) {

        PublicKeyAuthenticationClient pk = 
            new PublicKeyAuthenticationClient();

        pk.setUsername(user);
        // Open up the private key file
        SshPrivateKeyFile file = SshPrivateKeyFile
                .parse(new File(password));
        SshPrivateKey key = file.toPrivateKey(null);
        pk.setKeyfile(password);
        pk.setKey(key);
        // Try the authentication
        result = ssh.authenticate(pk);

    } else {

        // Create a password authentication instance
        PasswordAuthenticationClient pwd = 
            new PasswordAuthenticationClient();
        // Get the users name
        pwd.setUsername(user);
        // Get the password
        pwd.setPassword(password);

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

    System.out.println("Result fromssh.authenticate(pwd) " + result);
    // Evaluate the result
    if (result == AuthenticationProtocolState.COMPLETE) {

        // The connection is authenticated we can now do some real work!
        SftpClient sftp = ssh.openSftpClient();       
        System.out.println("openSftpClient");
        // Upload a file
        if(remoteFile != null && remoteFile.trim().length() > 0){
            sftp.put(localFile, remoteFile);
            System.out.println("======== no remote ======================================== file transfer success =======================================================================");
        }
        else    {
            System.out.println("================================================ file transfer starting =======================================================================");
            sftp.put(localFile);
            System.out.println("================================================ file transfer success =======================================================================");
        }


        // Quit
        sftp.quit();
        ssh.disconnect();
    }
    System.out.println(" END ");
}

【问题讨论】:

  • 您要发送的文件的大小是多少?
  • 文件大小各不相同,但通常在 100-150 KB 左右。这个特定的文件是 109874 字节

标签: java ssh


【解决方案1】:

ssh 客户端应该告诉服务器所需的最大数据包大小是多少,并且服务器应该遵守规范。

尝试使用不同的服务器并检查您自己服务器的最大数据包大小的配置。

【讨论】:

  • 我找不到在客户端设置最大数据包大小的任何方法。即便如此,如果客户端传输的默认值是 65535,为什么我们最终会让服务器抱怨 65580?
  • 您必须将新的数据包大小硬连线到源中才能在 j2sh 客户端上更改它——但这不是必需的。看看您是否可以在服务器端更改最大数据包大小。您正在与之通信的特定服务器可能无法容纳 65k 数据包。作为替代方案并排除行为不端的服务器,请尝试在另一台服务器上运行您的代码。
【解决方案2】:

看起来以下代码有效 - 我使用较低级别的“com.sshtools.j2ssh.sftp.SftpSubsystemClient”而不是“com.sshtools.j2ssh.SftpClient”并使用输入/输出流读取/写入文件:

    System.out.println("Result fromssh.authenticate(pwd) " + result);
    // Evaluate the result
    if (result == AuthenticationProtocolState.COMPLETE) {
        SftpSubsystemClient sftpSubsystemClient = ssh.openSftpChannel();
        com.sshtools.j2ssh.connection.Channel sftpChannel = sftpSubsystemClient;
        System.out.println("Local packet size: " + sftpChannel.getLocalPacketSize());
        System.out.println("Remote packet size: " + sftpChannel.getRemotePacketSize());

        SftpFile file = sftpSubsystemClient.openFile(remoteFile, SftpSubsystemClient.OPEN_CREATE | SftpSubsystemClient.OPEN_WRITE);

        FileAttributes attrs = file.getAttributes();
        attrs.setPermissions("rwxrwxrwx");
        sftpSubsystemClient.setAttributes(file, attrs);

        final int bufferSize = 4096;
        System.out.println("Creating buffered streams");
        BufferedInputStream in = new BufferedInputStream(new FileInputStream(localFile), bufferSize);
        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new SftpFileOutputStream(file)));

        int c;            
        while ((c = in.read()) != -1) {
            out.write(c);
        }
        System.out.println("Done writing streams");
        out.close();
        in.close();
        sftpSubsystemClient.close();            
        ssh.disconnect();
    }
    System.out.println(" END ");

真正有趣的是,我输出远程和本地数据包大小只是为了好玩,它们都等于 65535。看来这个 65580 消息确实是 SSH 服务器或 SSH 工具中的错误。

【讨论】:

    【解决方案3】:

    您无法更改 BLOCKSIZE。有几个地方提到了块大小。它们要么对某些读取或写入缓冲区使用固定值,要么在 Cipher 对象上调用getBlockSize(),该对象是 JVM 加密子系统的一部分。

    我无法重现您看到的错误。 SI 尝试了几个不同大小的文件,包括您提到的确切大小之一。这样的事情很容易受到客户端和服务器设置的影响。

    我的直觉是 j2ssh 库中有一个与密码块大小有关的错误,它通过不考虑某处的数据包标头来创建大于允许的块。我建议摆弄设置以查看是否可以强制客户端使用不同的密码。下载 j2ssh 源代码并尝试直接调试问题也可能会有所帮助。确定错误是否发生在第一个、最后一个或某个中间数据包上。

    【讨论】:

    • 有没有办法使用 java sshtools 设置协议版本?我正在谷歌搜索更多信息,看来这可能是由客户端使用的 ssh 协议版本引起的。
    猜你喜欢
    • 2017-01-17
    • 1970-01-01
    • 2015-10-02
    • 1970-01-01
    • 2017-10-14
    • 1970-01-01
    • 1970-01-01
    • 2014-07-18
    • 1970-01-01
    相关资源
    最近更新 更多