Skip to content

Some Question To Function (directoryContent , upload, download) of TransferMode.passive(FTPS) #60

@wang82426107

Description

@wang82426107

Hi, I have some question with Function (directoryContent , upload, download) , in the three Function, you use Socket Object To dataSocket.

    final Socket dataSocket = await Socket.connect(_socket.host, iPort);

but I use FTPS, this is Error, I try chang some code , I think solve the error with use RawSecureSocket , this is demo:

  Future<List<FTPEntry>> directoryContent({String? path}) async {
    // Enter passive mode
    FTPReply response = await _socket.openDataTransferChannel();

    String listCmd = path != null ? "LIST $path" : "LIST";
    _socket.sendCommandWithoutWaitingResponse(listCmd);

    // Data transfer socket
    int iPort = Utils.parsePort(response.message, _socket.supportIPV6);
    SecurityContext context = SecurityContext.defaultContext;
    RawSecureSocket dataSocket = await RawSecureSocket.connect(
      _socket.host,
      iPort,
      timeout: Duration(seconds: _socket.timeout),
      context: context,
      onBadCertificate: (certificate) => true,
    );

    response = await _socket.readResponse();
    bool isTransferCompleted = response.isSuccessCode();
    if (!isTransferCompleted && response.code != 125 && response.code != 150) {
      throw FTPConnectException('Connection refused. ', response.message);
    }

    final completer = Completer<List<FTPEntry>>();
    List<FTPEntry> lstFTPEntries = <FTPEntry>[];
    List<int> lstDirectoryListing = [];
    bool isStreamDone = false; // 标记流是否已处理完成
    String dataString ="";
    // 获取订阅对象
    final subscription = dataSocket.listen((RawSocketEvent event) {
      print("event: $event");
      if (event == RawSocketEvent.read) {
        var data = dataSocket.read();
        if (data != null) {
          lstDirectoryListing.addAll(data);
          String subDataString = utf8.decode(data);
          dataString = dataString + subDataString;
          print(dataString);
        }
      } else if (event == RawSocketEvent.closed) {
        isStreamDone = true; // 流自然关闭时标记
        dataSocket.close();
      }
    }, onError: (error) {
      isStreamDone = true; // 出错时也标记
      if (!completer.isCompleted) completer.completeError(error);
    });

    // 关键:等待asFuture(),但设置超时强制唤醒,避免无限阻塞
    await Future.any([
      subscription.asFuture(), // 正常等待流关闭
      Future.delayed(Duration(seconds: 10), () {
        // 超时未关闭,手动标记完成
        isStreamDone = true;
        print("Stream timeout, forcing completion");
      }),
    ]);

    // 无论流是自然关闭还是超时,都完成completer
    if (!completer.isCompleted) {
      completer.complete(lstFTPEntries);
    }

    // 此时一定能执行到这里
    final entries = await completer.future;

    // 解析逻辑保留
    dataString.split('\n').forEach((line) {
      if (line.trim().isNotEmpty) {
        lstFTPEntries.add(
          FTPEntry.parse(line.replaceAll('\r', ""), _socket.listCommand),
        );
      }
    });
    await dataSocket.close();
    return entries;
  }

zhe code have some timeout error, you need chang it.

I hope the code help for you.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions