唐瀚林 2024-10-18 11:13 采纳率: 0%
浏览 5

Apache FTPserver文件上传

Java 通过Apache Ftpserver实现ftp服务的时候我想实现文件不落地直接拿到文件流发走,而ftp的被动模式需要服务端开启一个TCP监听让客户端连接,服务器已经开启了服务,但是客户端始终连接不上是什么情况。

2024-10-18 10:53:31 31447 2 状态: 已登录
2024-10-18 10:53:31 31447 2 状态: 开始上传 /Users/tanghanlin/Desktop/O-v1.0.docx
2024-10-18 10:53:31 31447 2 命令: CWD /
2024-10-18 10:53:31 31447 2 响应: 250 Directory changed to /
2024-10-18 10:53:31 31447 2 命令: TYPE I
2024-10-18 10:53:31 31447 2 响应: 200 Command TYPE okay.
2024-10-18 10:53:31 31447 2 命令: PASV
2024-10-18 10:53:31 31447 2 响应: 227 Entering Passive Mode (127,0,0,1,215,26)
2024-10-18 10:53:31 31447 2 命令: STOR O-v1.0.docx
就一直卡在这里。



```java
package com.slorgs.server;

import org.apache.ftpserver.FtpServerFactory;
import org.apache.ftpserver.command.AbstractCommand;
import org.apache.ftpserver.command.CommandFactoryFactory;
import org.apache.ftpserver.ftplet.*;
import org.apache.ftpserver.impl.*;
import org.apache.ftpserver.listener.ListenerFactory;
import org.apache.ftpserver.usermanager.ClearTextPasswordEncryptor;
import org.apache.ftpserver.usermanager.PropertiesUserManagerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.*;
import java.nio.file.Files;
import java.nio.file.Paths;

/**
 * @author hanlin.tang
 */
public class FtpServer {

    private static final Logger log = LoggerFactory.getLogger(FtpServer.class);

    public static void start() {
        try {
            FtpServerFactory serverFactory = new FtpServerFactory();
            ListenerFactory factory = new ListenerFactory();
            factory.setPort(2221);
            serverFactory.addListener("default", factory.createListener());
            PropertiesUserManagerFactory userManagerFactory = new PropertiesUserManagerFactory();
            userManagerFactory.setFile(new File("/Users/tanghanlin/IdeaProjects/file_transfer_demo/src/main/resources/myusers.properties"));
            userManagerFactory.setPasswordEncryptor(new ClearTextPasswordEncryptor());
            UserManager userManager = userManagerFactory.createUserManager();
            serverFactory.setUserManager(userManager);
            CommandFactoryFactory commandFactoryFactory = new CommandFactoryFactory();
            commandFactoryFactory.addCommand("STOR", new CustomStoreCommand2());
            serverFactory.setCommandFactory(commandFactoryFactory.createCommandFactory());
            org.apache.ftpserver.FtpServer server = serverFactory.createServer();
            server.start();
        } catch (Exception ex) {
            log.error("Error occurred: {}", ex.getMessage(), ex);
        }
    }

    public static class CustomStoreCommand2 extends AbstractCommand {
        @Override
        public void execute(FtpIoSession session, FtpServerContext context, FtpRequest request) throws FtpException {
            ServerSocket serverSocket = null;
            Socket clientSocket = null;
            try {
                InetSocketAddress localAddress1 = (InetSocketAddress) session.getLocalAddress();
                serverSocket = new ServerSocket(0, 0, localAddress1.getAddress());
                int port = serverSocket.getLocalPort();
                log.info("Open port: {}", port);
                clientSocket = serverSocket.accept();
                InputStream dataInputStream = clientSocket.getInputStream();
                byte[] buffer = new byte[4096];
                int bytesRead;
                try (OutputStream o = Files.newOutputStream(Paths.get("/Users/tanghanlin/Desktop/sftp/sss.txt"))) {
                    while ((bytesRead = dataInputStream.read(buffer)) != -1) {
                        o.write(buffer, 0, bytesRead);
                        o.flush();
                    }
                }
                session.write(LocalizedFtpReply.translate(session, request, context,
                        FtpReply.REPLY_226_CLOSING_DATA_CONNECTION, "STOR", null));
            } catch (Exception e) {
                log.error("Error occurred during STOR: {}", e.getMessage(), e);
            } finally {
                closeResources(serverSocket, clientSocket);
            }
        }

        private void closeResources(ServerSocket serverSocket, Socket clientSocket) {
            try {
                if (clientSocket != null) clientSocket.close();
                if (serverSocket != null) serverSocket.close();
            } catch (IOException e) {
                log.error("Error closing resources: {}", e.getMessage());
            }
        }
    }
}


```

  • 写回答

1条回答 默认 最新

  • 越重天 新星创作者: Java技术领域 2024-10-18 11:52
    关注

    本答案参考 多次询问 ChatGPT-3.5 后选择的最佳回答,若是满意,还请采纳,谢谢

    1. 可能的原因分析
      • 防火墙限制
        • 服务器端可能存在防火墙阻止了客户端与服务器在被动模式下建立数据连接。虽然服务器在响应PASV命令时提供了一个地址和端口(227 Entering Passive Mode (127,0,0,1,215,26)),但如果防火墙阻止了客户端对该端口的访问,连接就会失败。例如,如果服务器运行在有严格网络安全策略的环境中,如企业内部网络的特定安全区域,防火墙可能被配置为只允许特定端口的入站连接,而被动模式下的临时端口可能不在允许范围内。
      • 网络地址转换(NAT)问题
        • 如果服务器位于一个使用NAT的网络环境中,服务器返回给客户端的本地地址(在PASV响应中的127.0.0.1)可能无法被客户端正确访问。因为127.0.0.1是本地回环地址,从客户端的角度来看,这个地址是无法直接连接的。例如,在一些家庭网络或企业网络中,路由器会进行NAT转换,当服务器返回127.0.0.1作为数据连接的地址时,客户端实际上无法通过这个地址建立连接。
      • 服务器配置错误
        • CustomStoreCommand2类的execute方法中,创建ServerSocket的方式可能存在问题。例如,serverSocket = new ServerSocket(0, 0, localAddress1.getAddress());这种创建方式可能在某些网络环境或特定的Java运行时环境下不被正确支持。而且在处理数据传输时,可能存在一些与FTP协议细节不完全匹配的情况,导致客户端在尝试建立数据连接时出现问题。
      • 客户端配置问题
        • 客户端可能没有正确配置来处理服务器的被动模式响应。例如,客户端可能没有正确解析服务器返回的PASV响应中的地址和端口信息,或者客户端的网络设置限制了它与服务器指定端口的连接。
    2. 解决建议
      • 防火墙设置
        • 检查服务器端的防火墙设置,确保允许FTP数据连接的端口通过。如果是在开发环境中,可以暂时关闭防火墙进行测试(但这在生产环境中是不安全的做法)。如果不能关闭防火墙,可以配置防火墙规则,允许来自客户端的对FTP数据端口的连接。例如,在Linux系统中使用iptables命令来添加允许特定端口范围(FTP数据端口范围通常是比较大的,因为是动态分配的)的入站规则。
      • 解决NAT问题
        • 对于NAT问题,可以考虑在服务器配置中设置正确的外部可访问地址。在Apache FtpServer中,可能需要通过一些配置选项来指定服务器在网络中的真实外部地址,而不是返回本地回环地址。例如,可以通过配置文件或者在创建FtpServerFactory时设置相关的网络地址属性。
      • 服务器端代码修正
        • CustomStoreCommand2类中,可以尝试使用更标准的方式创建ServerSocket。例如,serverSocket = new ServerSocket();,然后使用serverSocket.bind(new InetSocketAddress(localAddress1.getAddress(), 0));来绑定到本地地址的随机端口。同时,在处理FTP协议交互时,确保严格遵循FTP协议标准,例如在发送响应给客户端时的格式和时机。
      • 客户端检查
        • 检查客户端的配置选项,确保它能够正确解析服务器的PASV响应并尝试连接到正确的地址和端口。可以查看客户端的日志(如果有)来确定是否存在解析错误或者连接尝试失败的原因。如果是使用第三方的FTP客户端库,可以参考其文档来确保正确的配置。
    评论

报告相同问题?

问题事件

  • 创建了问题 10月18日