【问题标题】:FTPSClient throw exception javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshakeFTPSClient 抛出异常 javax.net.ssl.SSLHandshakeException:握手期间远程主机关闭连接
【发布时间】:2019-11-14 18:23:14
【问题描述】:

我需要帮助我正在尝试创建与上传文件的 FTP'Server 的连接。
我正在使用 java jdk1.8.0_45 的以下依赖项。当我运行我的代码时,它会建立连接并登录,但是当我尝试上传文件时,它会抛出 Exceptionupload empty file

Exception in thread "main" javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:980)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1363)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1391)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1375)
at org.apache.commons.net.ftp.FTPSClient._openDataConnection_(FTPSClient.java:619)
at org.apache.commons.net.ftp.FTPClient._storeFile(FTPClient.java:633)
at org.apache.commons.net.ftp.FTPClient.__storeFile(FTPClient.java:624)
at org.apache.commons.net.ftp.FTPClient.storeFile(FTPClient.java:1976)
at org.quorum.appnexusutility.transfer.TransferManager.uploadFile(TransferManager.java:176)
at org.quorum.appnexusutility.transfer.TransferManager.pushFile(TransferManager.java:220)
at org.quorum.appnexusutility.transfer.TransferManager.main(TransferManager.java:233)
Caused by: java.io.EOFException: SSL peer shut down incorrectly
at sun.security.ssl.InputRecord.read(InputRecord.java:505)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:961)
... 10 more

依赖

<dependency>
        <groupId>commons-net</groupId>
        <artifactId>commons-net</artifactId>
        <version>3.3</version>
</dependency>

下面的代码我更改主机可能不适合你

package org.quorum.appnexusutility.transfer;

import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.net.PrintCommandListener;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.net.ftp.FTPSClient;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSessionContext;
import javax.net.ssl.SSLSocket;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.Socket;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Date;
import java.util.Locale;


@Component
@Scope("prototype")
public class TransferManager {

    public Logger logger = LogManager.getLogger(TransferManager.class);

    // SSL/TLS
    private final Integer TENSECONDS  = 10*1000; // 10 second
    private final String protocol = "TLS";//"TLS";
    private Boolean isLogin = false;
    private Boolean isUpload = false;
    private String directoryPath;
    private String host;
    private Integer port;
    private String user;
    private String password;
    private FTPSClient ftpsClient;

    public TransferManager() { }

    public String getHost() { return host; }
    public TransferManager setHost(String host) {
        this.host = host;
        return this;
    }

    public Integer getPort() { return port; }
    public TransferManager setPort(Integer port) {
        this.port = port;
        return this;
    }

    public String getUser() { return user; }
    public TransferManager setUser(String user) {
        this.user = user;
        return this;
    }

    public String getPassword() { return password; }
    public TransferManager setPassword(String password) {
        this.password = password;
        return this;
    }

    public String getDirectoryPath() { return directoryPath; }
    public void setDirectoryPath(String directoryPath) {
        this.directoryPath = directoryPath;
    }

    public void open() throws IOException {
        //System.setProperty("jdk.tls.useExtendedMasterSecret", "false");
        //this.ftpsClient = new SSLSessionReuseFTPSClient();
        //ftpsClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out), true));
        if(this.port > 100) {
            this.ftpsClient = new FTPSClient(this.protocol, true);
        } else {
            this.ftpsClient = new FTPSClient(false);
        }
        this.ftpsClient.setControlKeepAliveTimeout(TENSECONDS);
        this.showServerReply(this.ftpsClient);
        logger.info("FTP :- Connection try :- IP :- (" + this.host + ") , Port :- " + this.port + " Start");
        this.ftpsClient.connect(this.host, this.port);
        this.ftpsClient.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out)));
        logger.info("FTP :- Connection try :- IP :- (" + this.host + ") , Port :- " + this.port + " Done");
        int reply = this.ftpsClient.getReplyCode();
        logger.info("FTP :- Connection Code :- " + reply);
        if(!FTPReply.isPositiveCompletion(reply)) {
            this.ftpsClient.disconnect();
            throw new IOException("Exception in connecting to FTP Server");
        }
        this.isLogin = this.ftpsClient.login(user, password);
        this.showServerReply(this.ftpsClient);
        logger.info("FTP :- Login Status :- " + this.isLogin);
    }

    private Boolean makeDirectory() throws IOException {
        Boolean isDirectoryCreate = false;
        if(this.isLogin && this.directoryPath != null) {
            isDirectoryCreate = this.ftpsClient.makeDirectory(this.directoryPath);
            this.showServerReply(this.ftpsClient);
            if (isDirectoryCreate) {
                logger.info("Successfully created directory: " + this.directoryPath);
            } else {
                logger.info("Failed to create directory. See server's reply.");
            }
        }
        return isDirectoryCreate;
    }

    //  if returns 250, folder exists  and if returned 550 folder does not exist***
    private Boolean isDirectoryExist() throws IOException {
        if(this.ftpsClient.cwd(this.directoryPath) == 550) {
            logger.info("Directory Not Exist");
            return false;
        } else {
            logger.info("Directory Exist");
            return true;
        }
    }

    // upload process
    public Boolean uploadFile(File file) throws Exception {
        if(this.isLogin && this.directoryPath != null) {
            if(!this.isDirectoryExist()) {
                // call when not exist
                this.makeDirectory();
            }
            this.ftpsClient.enterLocalPassiveMode();
            this.ftpsClient.execPBSZ(0);
            this.ftpsClient.execPROT("P");
            this.ftpsClient.setFileType(FTP.BINARY_FILE_TYPE);
            // only the text file can be upload
            //this.ftpsClient.setFileType(FTP.TELNET_TEXT_FORMAT);
            this.ftpsClient.changeWorkingDirectory(this.getDirectoryPath());
            logger.info("Current Directory " + this.ftpsClient.printWorkingDirectory());
            FileInputStream fileInputStream = new FileInputStream(file);
            String filePath = RandomStringUtils.randomAlphanumeric(8)+".txt";
            logger.info("Final Path :- " + filePath);
            //this.isUpload =
                    this.ftpsClient.storeFile(filePath, fileInputStream);
            if(this.isUpload) {
                logger.info("The file is uploaded successfully.");
            }
            // close the stream which use to store the file
            fileInputStream.close();
        }
        return this.isUpload;
    }

    // connection close for client
    public void close() throws IOException {
        if (this.ftpsClient.isConnected()) {
            this.ftpsClient.logout();
            this.ftpsClient.disconnect();
        }
    }

    public String getDirectoryPathRandom() {
        Date date = new Date();
        LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        int year  = localDate.getYear();
        int month = localDate.getMonthValue();
        int day   = localDate.getDayOfMonth();
        int hours = date.getHours();
        logger.info("Year :- (" + year + ") Month :- (" + month + ") Day :- (" + day + ") Hours :- (" + hours + ")");
        return year + "/"+ month + "/" + day + "/" + hours;
    }

    private void showServerReply(FTPSClient ftpsClient) {
        String[] replies = ftpsClient.getReplyStrings();
        if (replies != null && replies.length > 0) {
            for (String aReply : replies) {
                logger.info("SERVER: " + aReply);
            }
        }
    }
    // this method use to push the file from 1 server to other server
    public static void pushFile(String host, int port, String user, String password, File file) throws Exception {
        TransferManager transferManager = new TransferManager().setHost(host).setPort(port).setUser(user).setPassword(password);
        // we push the fiel on the base of yyyy/mm/dd/hr
        // first check if the dir exist then no need to create the directory
        transferManager.setDirectoryPath(transferManager.getDirectoryPathRandom());
        transferManager.open(); // open connection
        transferManager.uploadFile(file); // file
        transferManager.close(); // close connection
    }

    //======================FTP=========================
    //FTP URL: ftp.dlptest.com or ftp://ftp.dlptest.com/
    //FTP User: dlpuser@dlptest.com
    //Password: bbCKucPzfr4b9YXUY7tvsNKyh
    public static void main(String args[]) throws Exception {
        pushFile("ftps.xyzserver.com", 990, "macak", "Go447641", new File("C:\\Users\\Nabeel.Ahmed\\Desktop\\Study-Pending\\Detail Document.txt"));
    }
}

【问题讨论】:

    标签: java spring apache-commons-net


    【解决方案1】:

    这似乎是 SSL/TLS 协议版本问题的问题。浏览以下帖子SSL peer shut down incorrectly in Java你应该会得到答案。

    【讨论】:

      【解决方案2】:

      你可以尝试替换以下行

      private final String protocol = "TLS";//"TLS";
      

      private final String protocol = "TLSv1.1";
      

      【讨论】:

      【解决方案3】:

      经过大量的搜索,终于找到了解决方案,重用了prepareDataSocket的方法。

      import org.apache.commons.net.ftp.FTPSClient;
      import javax.net.ssl.SSLSession;
      import javax.net.ssl.SSLSessionContext;
      import javax.net.ssl.SSLSocket;
      import java.io.*;
      import java.lang.reflect.Field;
      import java.lang.reflect.Method;
      import java.net.Socket;
      import java.util.Locale;
      
      
      public class ModifiedFTPSClient extends FTPSClient {
      
          public ModifiedFTPSClient() {
              super("TLS", false);
          }
      
          public ModifiedFTPSClient(boolean isImplicit) {
              super("TLS", isImplicit);
          }
      
          @Override
          protected void _prepareDataSocket_(final Socket socket) throws IOException {
              if (socket instanceof SSLSocket) {
                  final SSLSession session = ((SSLSocket) _socket_).getSession();
                  if (session.isValid()) {
                      final SSLSessionContext context = session.getSessionContext();
                  try {
                      final Field sessionHostPortCache = context.getClass().getDeclaredField("sessionHostPortCache");
                      sessionHostPortCache.setAccessible(true);
                      final Object cache = sessionHostPortCache.get(context);
                      final Method method = cache.getClass().getDeclaredMethod("put", Object.class, Object.class);
                      method.setAccessible(true);
                      method.invoke(cache, String.format("%s:%s", socket.getInetAddress().getHostName(), String.valueOf(socket.getPort())).toLowerCase(Locale.ROOT), session);
                      method.invoke(cache, String.format("%s:%s", socket.getInetAddress().getHostAddress(), String.valueOf(socket.getPort())).toLowerCase(Locale.ROOT), session);
                  } catch (NoSuchFieldException e) {
                      throw new IOException(e);
                  } catch (Exception e) {
                      throw new IOException(e);
                  }
              } else {
                  throw new IOException("Invalid SSL Session");
              }
          }
      }
      

      上面的问题类TransferManager这样替换类

      private String user;
      private String password;
      private ModifiedFTPSClient ftpsClient;
      

      上面的问题类TransferManager替换open()方法中的值

      if(this.port > 100) {
          this.ftpsClient  = new ModifiedFTPSClient(true); // fro ftps
      } else {
          this.ftpsClient = new ModifiedFTPSClient(); // fro ftp
      }
      
      猜你喜欢
      • 2012-08-12
      • 2018-07-29
      • 2017-06-25
      • 2014-12-23
      • 2016-05-27
      • 1970-01-01
      • 2017-03-03
      • 2018-09-27
      相关资源
      最近更新 更多