Java SSH工具:SftpClient错误:远程计算机已断开连接:协议错误:数据包太长:65580

时间:2009-10-26 21:46:35

标签: java ssh

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

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

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

有什么想法吗?

我有以下使用Java Ssh Tools的实用程序方法(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 ");
}

3 个答案:

答案 0 :(得分:1)

ssh客户端应该告诉服务器所需的最大数据包大小是什么,服务器应该符合规范。

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

答案 1 :(得分:1)

看起来以下代码有效 - 我使用较低级别的“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工具中的一个错误。

答案 2 :(得分:0)

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

我无法重现您所看到的错误。 SI尝试使用几种不同大小的文件,包括您提到的确切大小。像这样的东西很容易受到客户端和服务器设置的影响。

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