Docker 中的 Apache FTP 客户端 运行 从外部服务器检索文件内容时出现问题
Apache FTP Client running in Docker has problem with retrieving files contents from external server
我使用 Apache FTP 客户端从 FTP 服务器检索文件内容。它 运行 在被动模式下,使用 retrieveFileStream 或 retrieveFile 检索,当我 运行 它没有 Docker。当我从 Docker 容器 运行 这个应用程序时出现问题。它正确连接、登录、检索文件列表。它在检索文件内容时出现问题 - 它无法检索文件的全部内容,只能检索其中的一部分。我认为这可能是一个缓冲区问题,我将所有缓冲区设置的值设置为巨大的数字,并且还尝试使用缓冲区从流中读取(正如有人在检索文件时遇到问题时在 Whosebug 上提出的那样),但没有成功。我还将 Docker 的 MTU 设置设置为我的正常网络使用的值,但它也没有帮助。
这是一些代码:
FTPClient ftpClient = new FTPClient();
ftpClient.setControlKeepAliveTimeout(120);
ftpClient.setDataTimeout(120000);
ftpClient.setBufferSize(1024000);
ftpClient.setReceiveBufferSize(1024000);
ftpClient.setReceieveDataSocketBufferSize(1024000);
LOGGER.trace("Trying to connect to host {}.", connectionSettings.getHost());
ftpClient.connect(connectionSettings.getHost());
int replyCode = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(replyCode)) {
ftpClient.disconnect();
LOGGER.error("Received negative reply code from host {}. Disconnected.", connectionSettings.getHost());
throw new FtpClientNotReadyException();
}
ftpClient.enterLocalPassiveMode();
LOGGER.trace("Received positive reply from host {}. Trying to log in.", connectionSettings.getHost());
try {
if (!ftpClient.login(connectionSettings.getUsername(), connectionSettings.getPassword())) {
LOGGER.warn("FTP Client login failed for user {}", connectionSettings.getUsername());
ftpClient.disconnect();
throw new FtpClientNotReadyException();
}
} catch (IOException e) {
ftpClient.disconnect();
throw e;
}
LOGGER.trace("Successfully logged in to host {} on account {}.", connectionSettings.getHost(),
connectionSettings.getUsername());
try {
if (Strings.isNotBlank(connectionSettings.getWorkingDirectory()) &&
!ftpClient.changeWorkingDirectory(connectionSettings.getWorkingDirectory())) {
LOGGER.warn("FTP Client could not change worked directory to {}.", connectionSettings.getWorkingDirectory());
throw new FtpClientNotReadyException();
}
} catch (IOException e) {
ftpClient.logout();
ftpClient.disconnect();
throw e;
}
InputStream retrievedFileContentInputStream = ftpClient.retrieveFileStream(fileName);
byte[] fileContentByteArray = retrievedFileContentInputStream.readAllBytes();
retrievedFileContentInputStream.close();
try {
checkFileSize(fileName, expectedFileSize, fileContentByteArray.length);
} catch (FileCorruptedException | FileBeingCurrentlyUploadedException e) {
throw e;
} finally {
if (!ftpClient.completePendingCommand()) {
LOGGER.trace("Complete pending command was not successful.");
}
LOGGER.trace("Completed pending command.");
}
这些是我尝试过的解决方案:
1) 从 InputStream 读取的缓冲区:
InputStream ins = ftpClient.retrieveFileStream(fileName);
ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
byte[] buff = new byte[2048];
int rc = 0;
int value =2048;
while ((rc = ins.read(buff, 0, value)) > 0) {
swapStream.write(buff, 0, rc);
}
byte[] fileByte = swapStream.toByteArray();
ftpClient.completePendingCommand();
2) 将输出流更改为输入流
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ftpClient.retrieveFile(fileName, outputStream);
outputStream.close();
byte[] fileContentByteArray = outputStream.toByteArray();
出现问题时我的典型日志输出:
Retrieved file size is lower than expected. Was: 228098. Expected: 236826.
Retrieved file size is lower than expected. Was: 1199. Expected: 1246.
由于 FTP 服务器以 ASCII 模式发送的不同行尾(回车符 return),与 Windows 不同平台上的客户端收到的字节数较少。
我使用 Apache FTP 客户端从 FTP 服务器检索文件内容。它 运行 在被动模式下,使用 retrieveFileStream 或 retrieveFile 检索,当我 运行 它没有 Docker。当我从 Docker 容器 运行 这个应用程序时出现问题。它正确连接、登录、检索文件列表。它在检索文件内容时出现问题 - 它无法检索文件的全部内容,只能检索其中的一部分。我认为这可能是一个缓冲区问题,我将所有缓冲区设置的值设置为巨大的数字,并且还尝试使用缓冲区从流中读取(正如有人在检索文件时遇到问题时在 Whosebug 上提出的那样),但没有成功。我还将 Docker 的 MTU 设置设置为我的正常网络使用的值,但它也没有帮助。
这是一些代码:
FTPClient ftpClient = new FTPClient();
ftpClient.setControlKeepAliveTimeout(120);
ftpClient.setDataTimeout(120000);
ftpClient.setBufferSize(1024000);
ftpClient.setReceiveBufferSize(1024000);
ftpClient.setReceieveDataSocketBufferSize(1024000);
LOGGER.trace("Trying to connect to host {}.", connectionSettings.getHost());
ftpClient.connect(connectionSettings.getHost());
int replyCode = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(replyCode)) {
ftpClient.disconnect();
LOGGER.error("Received negative reply code from host {}. Disconnected.", connectionSettings.getHost());
throw new FtpClientNotReadyException();
}
ftpClient.enterLocalPassiveMode();
LOGGER.trace("Received positive reply from host {}. Trying to log in.", connectionSettings.getHost());
try {
if (!ftpClient.login(connectionSettings.getUsername(), connectionSettings.getPassword())) {
LOGGER.warn("FTP Client login failed for user {}", connectionSettings.getUsername());
ftpClient.disconnect();
throw new FtpClientNotReadyException();
}
} catch (IOException e) {
ftpClient.disconnect();
throw e;
}
LOGGER.trace("Successfully logged in to host {} on account {}.", connectionSettings.getHost(),
connectionSettings.getUsername());
try {
if (Strings.isNotBlank(connectionSettings.getWorkingDirectory()) &&
!ftpClient.changeWorkingDirectory(connectionSettings.getWorkingDirectory())) {
LOGGER.warn("FTP Client could not change worked directory to {}.", connectionSettings.getWorkingDirectory());
throw new FtpClientNotReadyException();
}
} catch (IOException e) {
ftpClient.logout();
ftpClient.disconnect();
throw e;
}
InputStream retrievedFileContentInputStream = ftpClient.retrieveFileStream(fileName);
byte[] fileContentByteArray = retrievedFileContentInputStream.readAllBytes();
retrievedFileContentInputStream.close();
try {
checkFileSize(fileName, expectedFileSize, fileContentByteArray.length);
} catch (FileCorruptedException | FileBeingCurrentlyUploadedException e) {
throw e;
} finally {
if (!ftpClient.completePendingCommand()) {
LOGGER.trace("Complete pending command was not successful.");
}
LOGGER.trace("Completed pending command.");
}
这些是我尝试过的解决方案: 1) 从 InputStream 读取的缓冲区:
InputStream ins = ftpClient.retrieveFileStream(fileName);
ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
byte[] buff = new byte[2048];
int rc = 0;
int value =2048;
while ((rc = ins.read(buff, 0, value)) > 0) {
swapStream.write(buff, 0, rc);
}
byte[] fileByte = swapStream.toByteArray();
ftpClient.completePendingCommand();
2) 将输出流更改为输入流
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ftpClient.retrieveFile(fileName, outputStream);
outputStream.close();
byte[] fileContentByteArray = outputStream.toByteArray();
出现问题时我的典型日志输出:
Retrieved file size is lower than expected. Was: 228098. Expected: 236826.
Retrieved file size is lower than expected. Was: 1199. Expected: 1246.
由于 FTP 服务器以 ASCII 模式发送的不同行尾(回车符 return),与 Windows 不同平台上的客户端收到的字节数较少。