3

我使用 JSch 库开发 SFTP 客户端。

问题是两者getput方法的状态是-1。

这是我的代码:

class SftpClient {
    private static final Logger LOG = Logger.getLogger(SftpClient.class);

    /** Connection port number */
    public static final int PORT = 22;

    /** SECURED protocol name */
    private static final String PROTOCOL = "sftp";

    /** Connection time out in milliseconds */
    public static final int TIME_OUT = 5000;

    /** This class serves as a central configuration point, and as a factory for Session objects configured with these settings */
    private JSch _client;
    /** A session represents a connection to a SSH server */
    private Session _session;
    /** Channel connected to a SECURED server (as a subsystem of the SSH server) */
    private ChannelSftp _channelSftp;

    /**
     * Value returned by the last executed command.
     */
    private int _exitValue;

    /**
     * Computer contains the url, the login and the password to connect.
     */
    private Computer _computer;

    /**
     * Initialize a SECURED client
     * @param target - Machine we want to connect to
     */
    public SftpClient(Computer target) {
        _client = new JSch();
        _computer = target;
    }

    protected void connect() throws Exception {
        try {
            if (_client == null) {
                _client = new JSch();
            }
            if (_session == null) {
                _session = _client.getSession(_computer.getLogin(), _computer.getUrl(), PORT);
                Properties props = new Properties();
                props.put("StrictHostKeyChecking", "no");
                props.put("compression.s2c", "zlib,none");
                props.put("compression.c2s", "zlib,none");
                _session.setConfig(props);
                _session.setPassword(_computer.getPassword());
                if (LOG.isDebugEnabled()) {
                    LOG.debug("Connecting to "+_computer.getUrl()+" with login "+_computer.getLogin()+"...");
                }
            }
            if (!_session.isConnected()) {
                _session.connect(TIME_OUT);
            }
            // disconnect previous channel if it has not been killed properly
            if (_channelSftp != null && _channelSftp.isConnected()) {
                _channelSftp.disconnect();
            }
            _channelSftp = (ChannelSftp) _session.openChannel(PROTOCOL);
            _channelSftp.connect();
            if (LOG.isInfoEnabled()) {
                LOG.info("Connected to "+_computer.getUrl()+" with login "+_computer.getLogin());
            }
        } catch(JSchException e) {
            LOG.error("Auth failed", e);
            throw e;
        }
    }

    protected void connect(String path) throws Exception {
        connect();
        if (_channelSftp != null && _channelSftp.isConnected()) {
            _channelSftp.cd(path);
        }
    }

    public boolean get(final String remoteDirectory, final String remoteFile, final String localDirectory) throws Exception {
        boolean res = false;
        if (LOG.isInfoEnabled()) {
            LOG.info("Download file "+remoteDirectory+"/"+remoteFile+" from "+_computer+" in "+localDirectory);
        }
        if (remoteDirectory != null && remoteFile != null && !remoteFile.isEmpty() && localDirectory != null) {
            try {
                // connect to the server and change directory
                connect(remoteDirectory);
                // change local directory
                _channelSftp.lcd(localDirectory);
                // download the file, keeping the same name
                _channelSftp.get(remoteFile, remoteFile);
                // update exit value
                _exitValue = _channelSftp.getExitStatus();

                if (_exitValue == 0) {
                    res = true;
                }
                if (LOG.isDebugEnabled()) {
                    LOG.debug("Exit status is: "+_exitValue);
                }
            } catch(SftpException e){
                LOG.error("Auth failed", e);
                throw e;
            } finally {
                if (_channelSftp != null && _channelSftp.isConnected()) {
                    _channelSftp.disconnect();
                    _channelSftp.exit();
                }
            }
        } else {
            LOG.warn("Check remoteDirectory ('"+remoteDirectory+"') or remoteFile ('"+remoteFile+"') or localDirectory ('"+localDirectory+"').");
        }
        return res;
    }

    public void put(final File localFile, final String destPath) throws Exception {
        if (LOG.isInfoEnabled()) {
            LOG.info("Send file "+localFile+" to "+_computer+" in "+destPath);
        }
        if (localFile == null) {
            _exitValue = -1;
            LOG.error("The given local file is null. Aborting tranfer.");
            return;
        }
        if (!localFile.exists()) {
            _exitValue = -1;
            LOG.error("The given local file '"+localFile+"' does not exist. Aborting tranfer.");
            return;
        }
        final InputStream input = new FileInputStream(localFile);
        if (input == null || input.available() <= 0) {
            _exitValue = -1;
            LOG.error("Cannot read file "+localFile);
            return;
        }
        try {
            connect(destPath);
            _channelSftp.put(input, localFile.getName());
            _exitValue = _channelSftp.getExitStatus();
            if (LOG.isDebugEnabled()) {
                LOG.debug("Exit status is: "+_exitValue);
            }
        } catch(SftpException e){
            LOG.error("Auth failed", e);
            throw e;
        } finally {
            if (_channelSftp != null && _channelSftp.isConnected()) {
                _channelSftp.disconnect();
                _channelSftp.exit();
            }
            IOUtils.closeQuietly(input);
        }
    }

    public void disconnect() {
        if (_channelSftp != null && _channelSftp.isConnected()) {
            _channelSftp.disconnect();
            _channelSftp.exit();
        }
        if (_session != null && _session.isConnected()) {
            _session.disconnect();
            if (LOG.isInfoEnabled()) {
                LOG.info("SECURED FTP disconnected");
            }
        }
    }
}

不会抛出异常。

顺便说一句,我要上传和下载的文件是tar文件。Jsch 有 FTP 二进制模式吗?

文件传输良好。我可以正确使用它们,但我担心退出状态。

我查看了Jsch API,它说:

The exit status is only available for certain types of channels, and only after the channel was closed (more exactly, just before the channel is closed).

我如何知道退出状态是否可用ChannelSftp

4

1 回答 1

3

查看源代码,它看起来没有为 SFTP 实现 ExitStatus

channel.setExitStatus(reason_code);

在 Session 类中仅针对以下两种情况实现

case SSH_MSG_CHANNEL_OPEN_FAILURE:
case SSH_MSG_CHANNEL_REQUEST:

对于我测试的成功场景,至少没有调用这两种情况。

于 2013-02-21T17:04:05.237 回答