14

When the code below has finished running, netstat -a|grep sftp shows an open SFTP connection. It also shows up as an open connection in JProfiler.

channel.isConnected() in the finally block prints false. Any ideas why the connections is not being closed as I'm at a loss?

public static void clean() {
    com.jcraft.jsch.ChannelSftp channel = null;
    try {
        channel = Helper.openNewTLSftpChannel();
        channel.connect();
        channel.cd(remoteFileDirectory);

        List<ChannelSftp.LsEntry> list = channel.ls("*." + fileType);
        for (ChannelSftp.LsEntry file : list) {
            String fileName = file.getFilename();
            DateTime fileDate = new DateTime(parseDateFromFileName(fileName));

            //if this file is older than the cutoff date, delete from the SFTP share
            if (fileDate.compareTo(cleanupCutoffdate) < 0) {
                channel.rm(fileName);
            }
        }
    } catch (Exception exception) {
        exception.printStackTrace();
    } finally {
        if (channel != null) {
            channel.disconnect();
            System.out.println(channel.isConnected());
        }
    }
}

Adding openNewTLSftpChannel() below:

public static ChannelSftp openNewSftpChannel(String privateKeyFileName, String password, String username, String host, int port)
        throws ConfigurationErrorException {

    JSch jsch = new JSch();
    File sftpPrivateFile = new File(privateKeyFileName);
    Channel channel;
    try {
        if (!sftpPrivateFile.canRead()) {
            throw new ConfigurationErrorException("File access error: " + sftpPrivateFile.getAbsolutePath());
        }
        jsch.addIdentity(sftpPrivateFile.getAbsolutePath(), password);
        Session session = jsch.getSession(username, host, port);
        java.util.Properties config = new java.util.Properties();
        config.put("StrictHostKeyChecking", "no");
        session.setConfig(config);
        session.connect();
        channel = session.openChannel("sftp");
    } catch (JSchException jschException) {
        throw new ConfigurationErrorException("File access error: " + sftpPrivateFile.getAbsolutePath());
    }
    return (ChannelSftp) channel;
}
Michael
  • 13,838
  • 18
  • 52
  • 81

2 Answers2

27

If you take a look at the JSCH examples for SFTP you'll see how the session is terminated:

//setup Session here 
...
session.connect();
...


Channel channel = session.openChannel("sftp");
channel.connect();
ChannelSftp sftpChannel = (ChannelSftp) channel;

...run sftp logic...

//close sessions here
sftpChannel.exit();
session.disconnect();

You'll notice that there are two parts to the connection and disconnection; the Session object and the Channel object.

In my code I use the Session object to set my authentication information, and the Channel object to execute the sftp commands I need.

In your instance, you're creating the Session object in your openNewSftpChannel method, but it is never closed, hence your session stays alive.

For further context, check out the examples.

Community
  • 1
  • 1
Robert H
  • 11,520
  • 18
  • 68
  • 110
  • One can have multiple channels inside of one session (both at the same time as well as sequentially), therefore it is a good thing that the session is not auto-closed when one channel is closed. – Paŭlo Ebermann May 11 '13 at 23:49
  • This is not true -- exit just calls disconnect. Nothing else. – Mate Varga Dec 19 '16 at 12:42
  • 1
    sftpChannel.exit() calls the disconnect method via the Channel class, which ChannelSftp inherits (line 494 of Channel.java), session.disconnect is invoked via its own disconnect method (line 1545 of Session.java). – Robert H Dec 19 '16 at 16:19
  • @RobertH Does disconnecting a sftp session terminates / exits all open channels too? – Aswath May 27 '22 at 03:15
  • @Ayrush To be honest it's been quite a wile since I've used JSCH so I am not up to date on the library, that said if I recall correctly disconnect only worked on the session object created and would have no effect on other open channels – Robert H May 31 '22 at 14:34
  • Session.disconnect() calls Channel.disconnect(session object) which goes over the channels in the pool of channels and calls channels[i].disconnect(), synchronized on the pool. Ver. 0.1.55. – zmeeagain May 23 '23 at 09:38
8

Robert H is correct, you need to exit your channel and disconnect your session. I wanted to add that the session exists even when the channel has been closed. Since you create your session within a try block inside a method, it seems you have lost your session, but you can get it back using 'getSession' on your sftpChannel channel.

You can change your finally block to this:

} finally {
    if (channel != null) {
        Session session = channel.getSession();
        channel.disconnect();
        session.disconnect();
        System.out.println(channel.isConnected());
    }
}
Damienknight
  • 1,876
  • 2
  • 18
  • 34