Flutter FTP服务器搭建插件ftp_server的使用

发布于 1周前 作者 wuwangju 来自 Flutter

Flutter FTP服务器搭建插件 ftp_server 的使用

ftp_server 是一个用于在 Dart 中实现简单 FTP 服务器的包。它支持读写和只读模式,适用于各种用例。该服务器允许客户端连接并执行标准的 FTP 操作,如列出目录、检索文件、存储文件等。

特性

  • 被动和主动模式:支持被动和主动数据连接。
  • 文件操作:检索、存储、删除和列出文件。
  • 目录操作:更改、创建和删除目录。
  • 只读模式:禁用写操作以增强安全性。
  • 身份验证:基本用户名和密码身份验证。

兼容性

该包已在 macOS 上进行了测试。对于 Linux 和 Windows,已实现 CI/CD 测试用例,以确保代码运行和功能正常。

使用方法

启动服务器

以下是如何启动 FTP 服务器的示例:

import 'package:ftp_server/ftp_server.dart';

void main() async {
  final server = FtpServer(
    port: 21,
    username: 'user',
    password: 'pass',
    sharedDirectories: ['/home/user/ftp'],
    startingDirectory: 'ftp',
    serverType: ServerType.readAndWrite, // 或者 ServerType.readOnly
  );

  await server.start();
}

支持的操作

服务器支持以下 FTP 命令:

命令 描述
USER <username> 设置用户名进行身份验证。
PASS <password> 设置密码进行身份验证。
QUIT 关闭控制连接。
PASV 进入被动模式。
PORT <host-port> 进入主动模式。
LIST [<directory>] 列出指定目录或当前目录中的文件。
RETR <filename> 检索指定文件。
STOR <filename> 存储文件。
CWD <directory> 更改当前目录。
CDUP 更改为父目录。
MKD <directory> 创建新目录。
RMD <directory> 删除目录。
DELE <filename> 删除文件。
PWD 打印当前目录。
SYST 返回系统类型。
NOOP 不执行任何操作(用于保持连接)。
SIZE <filename> 返回指定文件的大小。

身份验证

要启用身份验证,在创建 FtpServer 实例时提供 usernamepassword 参数。然后,服务器将要求客户端使用这些凭据登录。

只读模式

要以只读模式运行服务器,将 serverType 参数设置为 ServerType.readOnly。在此模式下,修改文件系统的命令(例如 STORDELEMKDRMD)将被禁用。

示例 Demo

下面是一个完整的 Flutter 应用程序示例,演示如何使用 ftp_server 包来启动和停止 FTP 服务器,并选择共享目录。

// ignore_for_file: avoid_print

import 'dart:io';
import 'dart:isolate';
import 'dart:math';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:ftp_server/ftp_server.dart';
import 'package:ftp_server/server_type.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:shared_preferences/shared_preferences.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  MyAppState createState() => MyAppState();
}

class MyAppState extends State<MyApp> {
  FtpServer? ftpServer;
  String serverStatus = 'Server is not running';
  String connectionInfo = 'No connection info';
  String directoryPath = 'No directory chosen';
  bool isLoading = false;
  Isolate? isolate;
  ReceivePort? receivePort;
  int? port;

  @override
  void initState() {
    super.initState();
    if (Platform.isAndroid) {
      _requestPermission();
    }
    _loadDirectory();
  }

  Future<void> _requestPermission() async {
    if (await Permission.manageExternalStorage.isDenied) {
      await Permission.manageExternalStorage.request();
    }
  }

  Future<void> _loadDirectory() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    String? savedDirectory = prefs.getString('serverDirectory');
    if (savedDirectory != null) {
      setState(() {
        directoryPath = savedDirectory;
      });
    }
  }

  Future<String?> getIpAddress() async {
    // Implement your method to get device IP address here
    return '192.168.1.100'; // Example IP address
  }

  Future<String?> pickDirectory() async {
    String? selectedDirectory = await FilePicker.platform.getDirectoryPath();
    if (selectedDirectory != null) {
      SharedPreferences prefs = await SharedPreferences.getInstance();
      await prefs.setString('serverDirectory', selectedDirectory);
      setState(() {
        directoryPath = selectedDirectory;
      });
    }
    return selectedDirectory;
  }

  Future<void> toggleServer() async {
    setState(() {
      isLoading = true;
    });

    if (ftpServer == null) {
      SharedPreferences prefs = await SharedPreferences.getInstance();
      String? serverDirectory = prefs.getString('serverDirectory');

      if (serverDirectory == null) {
        serverDirectory = await pickDirectory();
        if (serverDirectory != null) {
          await prefs.setString('serverDirectory', serverDirectory);
        } else {
          setState(() {
            isLoading = false;
          });
          return;
        }
      }

      var server = FtpServer(
        port ?? Random().nextInt(65535),
        sharedDirectories: [serverDirectory],
        serverType: ServerType.readAndWrite,
        logFunction: (p0) => print(p0),
      );

      Future serverFuture = server.start();
      ftpServer = server;
      var address = await getIpAddress();

      setState(() {
        serverStatus = 'Server is running';
        connectionInfo = 'Connect using FTP client:\nftp://$address:${server.port}';
        isLoading = false;
      });

      await serverFuture;
    } else {
      await ftpServer!.stop();
      ftpServer = null;
      setState(() {
        serverStatus = 'Server is not running';
        connectionInfo = 'No connection info';
        isLoading = false;
      });
    }
  }

  @override
  void dispose() {
    receivePort?.close();
    isolate?.kill(priority: Isolate.immediate);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Flutter FTP Server'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(serverStatus),
              const SizedBox(height: 20),
              Text(connectionInfo),
              const SizedBox(height: 20),
              Text('Directory: $directoryPath'),
              const SizedBox(height: 20),
              isLoading
                  ? const CircularProgressIndicator()
                  : Row(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        ElevatedButton(
                          onPressed: toggleServer,
                          child: Text(
                            ftpServer == null ? 'Start Server' : 'Stop Server',
                          ),
                        ),
                        const SizedBox(width: 20),
                        ElevatedButton(
                          onPressed: pickDirectory,
                          child: const Text('Pick Directory'),
                        ),
                      ],
                    ),
            ],
          ),
        ),
      ),
    );
  }
}

这个示例展示了如何在 Flutter 应用中集成 ftp_server 包,并提供了启动和停止 FTP 服务器的功能,同时还可以选择共享目录。


更多关于Flutter FTP服务器搭建插件ftp_server的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter FTP服务器搭建插件ftp_server的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中搭建FTP服务器并使用ftp_server插件涉及到多个步骤,包括配置服务器、处理连接和传输文件等。虽然Flutter主要用于构建跨平台的移动应用,但可以通过使用Dart的VM(虚拟机)来运行服务器端的代码。以下是一个使用ftp_server插件搭建FTP服务器的基本示例代码。

首先,你需要确保你的Flutter环境已经设置好,并且已经添加了ftp_server依赖。在你的pubspec.yaml文件中添加以下依赖:

dependencies:
  ftp_server: ^x.y.z  # 请替换为最新版本号

然后运行flutter pub get来安装依赖。

由于Flutter本身是为客户端应用设计的,我们将在Dart VM环境中运行这个示例。因此,你需要创建一个单独的Dart文件(例如ftp_server.dart)来运行服务器代码。

ftp_server.dart

import 'dart:io';
import 'package:ftp_server/ftp_server.dart';

void main() async {
  // 定义FTP服务器的配置
  var config = FtpServerConfig(
    ip: InternetAddress.anyIPv4, // 监听所有IPv4地址
    port: 21, // FTP默认端口
    anonymous: false, // 不允许匿名登录
    userManager: InMemoryUserManager()
      ..addUser("user", "password", "/path/to/ftp/root"), // 添加用户及其密码和根目录
  );

  // 创建FTP服务器实例
  var ftpServer = FtpServer(config);

  // 启动服务器
  await ftpServer.start();
  print("FTP服务器已启动,监听端口 ${config.port}");

  // 为了保持服务器运行,我们在这里使用一个简单的循环
  stdin.listen((_) => null); // 等待用户输入以保持进程活跃(Ctrl+C停止服务器)
}

说明

  1. FtpServerConfig: 配置FTP服务器,包括监听IP、端口、是否允许匿名登录以及用户管理。
  2. InMemoryUserManager: 内存中的用户管理器,用于添加和管理用户。在这个例子中,我们添加了一个用户user,密码为password,其根目录为/path/to/ftp/root(请替换为实际的路径)。
  3. FtpServer: 创建FTP服务器实例。
  4. ftpServer.start(): 启动FTP服务器。
  5. stdin.listen((_) => null): 保持服务器运行,等待用户输入(在实际应用中,你可能会用更优雅的方式来管理服务器的生命周期)。

运行服务器

使用Dart VM运行ftp_server.dart文件:

dart ftp_server.dart

注意事项

  • 确保/path/to/ftp/root目录存在并且具有适当的读写权限。
  • 由于FTP通常用于传输文件,因此确保防火墙设置允许从你的客户端到服务器的21端口的连接。
  • 在生产环境中,你可能需要更复杂的用户管理和权限控制。
  • 这个示例仅用于演示目的,实际应用中需要考虑更多的安全性和错误处理。

这样,你就搭建了一个基本的FTP服务器,并且可以使用FTP客户端(如FileZilla)连接到这个服务器,使用用户名user和密码password进行登录。

回到顶部