Java 什么';通过commons net重试上传到FTP的正确方法是什么?
我在处理服务器时遇到问题,尽管我使用ftpClient.setControlKeepAliveTimeout发送了保持活动的请求,但该服务器仍会关闭FTP控制连接(控制连接保持活动间隔秒); 有时它也只是因为SocketException而消失,而不是正常的FTPConnectionClosedException。总而言之,FTP是一个非常狡猾的协议,我使用了很多,我连接的每台服务器都需要一些调整,但是这一个给了我一个非常困难的时间 我知道我可能会做很多错事,我的问题是,是否有一些解决方案已经在FTP上实现了重试,以防您失去控制连接,因为这不是什么应该令人震惊的事情(代理/防火墙有时只是随机失去您的连接)。或者有没有更优雅的方法来解决这个问题 我有这样的东西Java 什么';通过commons net重试上传到FTP的正确方法是什么?,java,ftp,apache-commons,Java,Ftp,Apache Commons,我在处理服务器时遇到问题,尽管我使用ftpClient.setControlKeepAliveTimeout发送了保持活动的请求,但该服务器仍会关闭FTP控制连接(控制连接保持活动间隔秒); 有时它也只是因为SocketException而消失,而不是正常的FTPConnectionClosedException。总而言之,FTP是一个非常狡猾的协议,我使用了很多,我连接的每台服务器都需要一些调整,但是这一个给了我一个非常困难的时间 我知道我可能会做很多错事,我的问题是,是否有一些解决方案已经在
public void store(File fileToUpload) throws IOException, InterruptedException {
String filename = fileToUpload.getName();
int retries = 0;
while (true) {
try {
ftpClient.storeFile(filename, inputStreamFactory.getInputStream(fileToUpload));
} catch (FTPConnectionClosedException | SocketException exception) {
LOGGER.debug("Control connection lost uploading {}, continuing.", filename);
}
// This sleep is because there's an anti-malware in the servers which makes the file not to appear
// available immediately after an upload
LOGGER.debug("Waiting {} milliseconds for anti-malware protection to process file", WAIT_AFTER_UPLOAD_MILLISECONDS);
threadWrapper.sleep(WAIT_AFTER_UPLOAD_MILLISECONDS);
if (!ftpClient.isConnected()) {
connect();
}
LOGGER.debug("Checking if {} is already uploaded", filename);
if (ftpFileChecker.isFileCompleted(listFiles(null), filename, fileToUpload.length())) {
// Note this is likely to happen every time since their server will close the control
// connection quite fast and FTPClient uses it at the end of storeFile
LOGGER.debug("File {} was uploaded correctly", filename);
break;
} else {
if (++retries > MAX_RETRIES) {
throw new RemoteTimeoutException("Could not upload file, max retries exceeded");
} else {
LOGGER.info("File {} was not uploaded, retrying", filename);
}
}
}
}
public void connect() throws IOException, InterruptedException {
int retries = 0;
while (true) {
try {
ftpClient = ftpClientFactory.createFtpClient();
ftpClient.connect(server, FTP_PORT);
if (!ftpClient.login(username, password)) {
LOGGER.error("Login to FTP failed");
throw new ConfigurationException("Login to FTP failed");
}
ftpClient.enterLocalPassiveMode();
ftpClient.setControlKeepAliveTimeout(CONTROL_CONNECTION_KEEP_ALIVE_INTERVAL_SECONDS);
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
ftpClient.changeWorkingDirectory(uploadDir);
break;
} catch (FTPConnectionClosedException | SocketException exception) {
if (++retries > MAX_RETRIES) {
throw new RemoteTimeoutException("Could not upload file, max retries exceeded", exception);
} else {
LOGGER.info("Could not login, retrying");
}
}
LOGGER.debug("Sleeping {} milliseconds before trying to reconnect", WAIT_BETWEEN_CONNECT_RETRIES_MILLISECONDS);
threadWrapper.sleep(WAIT_BETWEEN_CONNECT_RETRIES_MILLISECONDS);
}
}
public FTPFile[] listFiles(String directory) throws IOException, InterruptedException {
int retries = 0;
while (true) {
try {
return ftpClient.listFiles(directory);
} catch (FTPConnectionClosedException exception) {
LOGGER.debug("Control connection lost when listing files, continuing");
} catch (SocketException exception) {
LOGGER.debug("Socket exception when listing files, continuing");
}
if (!ftpClient.isConnected()) {
connect();
}
if (++retries > MAX_RETRIES) {
throw new RemoteTimeoutException("Could not list files, max retries exceeded");
} else {
LOGGER.info("Could not list files, retrying");
}
}
}
现在我在listFiles上发现SocketException管道断裂,我无法再找出它,因为在我的本地服务器上它工作得非常完美,但在这个特定的服务器上(提示它运行在Windows NT-):(-它运行一些恶意软件保护,防止文件立即出现在服务器上,并且明显位于一些非常奇怪的防火墙后面,并且在大约5秒钟后会断开空闲连接,他们不会更改配置,因为他们是一家大公司,并声称它适用于其他所有人)
我尝试了VFS,并在其他FTP客户端上进行了调查,但我发现似乎没有一个能够解决问题,更没有帮助的是,它们中的大多数(如ftp4j)都不在maven central,这真的让我推迟了尝试,除非有保证它能解决我的问题
欢迎任何帮助
编辑:给定的代码反映了这一点的开始复杂性,我的当前解决方案更稳定,更复杂,但它并不优雅,所以如果有人愿意贡献一个好的解决方案,我将问题打开。
< P>如果使用Spring,那么考虑Spring重试。我相信最新的Maven版本是: <dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>1.1.2.RELEASE</version>
</dependency>
org.springframework.retry
春季重试
1.1.2.1发布
如果它像重试包装器一样简单,我就不会为此发表文章了,这个代码所在的项目已经有了类似于spring发布的重试实用程序,但这对FTP不好