Flutter端口扫描插件dart_port_scanner的使用

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

Flutter端口扫描插件dart_port_scanner的使用

dart_port_scanner 是一个简单而快速的TCP和UDP端口扫描器插件。本文将介绍如何在Flutter应用中使用该插件进行端口扫描,并提供完整的示例代码。

使用方法

TcpScannerTask

TcpScannerTask 允许异步执行扫描任务,并提供了基本的方法来控制任务。你可以通过设置 shuffle 参数为 true 来打乱端口顺序,默认情况下,套接字连接超时时间为2秒。如果在此时间内未收到响应,则端口将被标记为 closed。你可以通过设置 socketTimeout 选项来更改此值,默认值为1000毫秒。你还可以通过定义 parallelism 选项指定要使用的隔离数,默认值为4。

示例代码

以下是一个简单的TCP端口扫描任务示例:

import 'dart:async';
import 'package:dart_port_scanner/dart_port_scanner.dart';

void main() async {
  final host = 'mfazrinizar.com';
  final ports = List.generate(990, (i) => 10 + i)
    ..add(5000)
    ..addAll([1100, 1110]);
  var stopwatch = Stopwatch();
  stopwatch.start();

  try {
    await TcpScannerTask(host, ports, shuffle: true, parallelism: 2)
        .start()
        .then((report) => print('Host ${report.host} scan completed\n'
            'Scanned ports:\t${report.ports.length}\n'
            'Open ports:\t${report.openPorts}\n'
            'Status:\t${report.status}\n'
            'Elapsed:\t${stopwatch.elapsed}\n'))
        // 捕获扫描期间的错误
        .catchError((error) => stderr.writeln(error));
  } catch (e) {
    // 在构造函数中捕获异常
    stderr.writeln('Error: $e');
  }
}

UdpScannerTask

UdpScannerTask 类似于 TcpScannerTask,但用于UDP端口扫描。默认情况下,套接字连接超时时间为1秒。如果在此时间内未收到响应,则端口将被标记为 filtered。你可以通过设置 socketTimeout 选项来更改此值,默认值为1000毫秒。

示例代码

以下是一个简单的UDP端口扫描任务示例:

import 'dart:async';
import 'package:dart_port_scanner/dart_port_scanner.dart';

void main() async {
  final host = 'mfazrinizar.com';
  final ports = List.generate(990, (i) => 10 + i)
    ..add(5000)
    ..addAll([1100, 1110]);
  var stopwatch = Stopwatch();
  stopwatch.start();

  try {
    await UdpScannerTask(host, ports, shuffle: true, parallelism: 2)
        .start()
        .then((report) => print('Host ${report.host} scan completed\n'
            'Scanned ports:\t${report.ports.length}\n'
            'Open ports:\t${report.openPorts}\n'
            'Filtered ports:\t${report.filteredPorts}\n'
            'Status:\t${report.status}\n'
            'Elapsed:\t${stopwatch.elapsed}\n'))
        // 捕获扫描期间的错误
        .catchError((error) => stderr.writeln(error));
  } catch (e) {
    // 在构造函数中捕获异常
    stderr.writeln('Error: $e');
  }
}

取消任务和获取进度报告

你可以使用 cancel() 方法取消任务,它返回一个带有扫描结果的Future。请注意,在取消任务后,start() 方法的Future将不会返回任何结果。

你可以使用 report 字段在扫描期间请求状态更新。以下是一个示例,展示如何定期获取扫描进度报告:

var ports = List.generate(65535, (i) => 0 + i);
var stopwatch3 = Stopwatch();
stopwatch3.start();
try {
  var scannerTask2 = TcpScannerTask(host, ports, parallelism: 100);
  Timer.periodic(Duration(seconds: 1), (timer) {
    scannerTask2.report.then((report) {
      var percents = 100.0 * (report.openPorts.length + report.closedPorts.length) / report.ports.length;
      var scanned = report.closedPorts.length + report.openPorts.length;
      print('Host $host scan progress ${percents.toStringAsFixed(1)}%\n'
          'Scanned ports:\t$scanned of ${report.ports.length}\n'
          'Open ports:\t${report.openPorts}\n'
          'Status:\t${report.status}\n'
          'Elapsed:\t${stopwatch3.elapsed}\n');
      if (report.status == PortScannerTaskReportStatus.finished) {
        timer.cancel();
      }
    });
  });
  await scannerTask2.start();
} catch (error) {
  stderr.writeln(error);
}

完整示例

以下是一个完整的示例,展示如何根据用户输入选择不同的扫描类型(TCP、UDP、STCP、SUDP)并执行相应的扫描任务:

import 'dart:async';
import 'dart:io';
import 'package:dart_port_scanner/dart_port_scanner.dart';

enum ScanType { tcp, udp, stcp, sudp }

void main() async {
  print(
      "Enter 'TCP', 'UDP', 'STCP', or 'SUDP' ('S' stands for single) to start the scanner: ");
  String? input = stdin.readLineSync();

  if (input != null) {
    ScanType? scanType = _parseScanType(input);
    if (scanType != null) {
      try {
        switch (scanType) {
          case ScanType.tcp:
            await _performScan(
              host: 'mfazrinizar.com',
              ports: List.generate(1000, (i) => 10 + i)
                ..add(5000)
                ..addAll([1100, 1110]),
              scannerTask: (host, ports, shuffle, parallelism, timeout) =>
                  TcpScannerTask(host, ports,
                      shuffle: shuffle,
                      parallelism: parallelism,
                      socketTimeout: timeout),
              shuffle: true,
              parallelism: 2,
              timeout: Duration(milliseconds: 10),
            );
            break;
          case ScanType.udp:
            await _performScan(
              host: 'mfazrinizar.com',
              ports: List.generate(1000, (i) => 10 + i)
                ..add(5000)
                ..addAll([1100, 1110]),
              scannerTask: (host, ports, shuffle, parallelism, timeout) =>
                  UdpScannerTask(host, ports,
                      shuffle: shuffle,
                      parallelism: parallelism,
                      socketTimeout: timeout),
              shuffle: true,
              parallelism: 2,
              timeout: Duration(milliseconds: 1000),
            );
            break;
          case ScanType.stcp:
            await _performSingleScan(
              host: 'mfazrinizar.com',
              ports: [80, 443, 25565],
              scannerTask: (host, ports, shuffle, parallelism, timeout) =>
                  TcpScannerTask(host, ports,
                      shuffle: shuffle,
                      parallelism: parallelism,
                      socketTimeout: timeout),
              shuffle: true,
              parallelism: 4,
              timeout: Duration(milliseconds: 10000),
            );
            break;
          case ScanType.sudp:
            await _performSingleScan(
              host: 'mfazrinizar.com',
              ports: [25566, 25565],
              scannerTask: (host, ports, shuffle, parallelism, timeout) =>
                  UdpScannerTask(host, ports,
                      shuffle: shuffle,
                      parallelism: parallelism,
                      socketTimeout: timeout),
              shuffle: false,
              parallelism: 1,
              timeout: Duration(milliseconds: 5000),
            );
            break;
        }
      } catch (e) {
        print("Error caught: ${e.toString()}");
      }
    } else {
      print("Invalid input. Please enter 'TCP', 'UDP', 'STCP', or 'SUDP'.");
    }
  }
}

// 解析用户输入的扫描类型
ScanType? _parseScanType(String input) {
  switch (input.toUpperCase()) {
    case "TCP":
      return ScanType.tcp;
    case "UDP":
      return ScanType.udp;
    case "STCP":
      return ScanType.stcp;
    case "SUDP":
      return ScanType.sudp;
    default:
      return null;
  }
}

typedef ScannerTask = dynamic Function(String host, List<int> ports,
    bool shuffle, int parallelism, Duration timeout);

// 执行扫描任务
Future<void> _performScan({
  required String host,
  required List<int> ports,
  required ScannerTask scannerTask,
  required bool shuffle,
  required int parallelism,
  required Duration timeout,
}) async {
  var stopwatch1 = Stopwatch()..start();

  // 简单扫描
  try {
    print('Starting simple scan...');
    await scannerTask(host, ports, shuffle, parallelism, timeout)
        .start()
        .then((report) {
      print('Host ${report.host} scan completed\n'
          'Scanned ports:\t${report.ports.length}\n'
          'Open ports:\t${report.openPorts}\n'
          'Closed ports:\t${report.closedPorts}\n'
          'Filtered ports:\t${report.filteredPorts}\n'
          'Status:\t${report.status}\n'
          'Elapsed:\t${stopwatch1.elapsed}\n');
    }).catchError((error) => stderr.writeln(error));
  } catch (e) {
    stderr.writeln('Error: $e');
  }

  // 通过延迟取消扫描
  var stopwatch2 = Stopwatch()..start();
  try {
    print('Starting scan with cancellation...');
    var scannerTask1 = scannerTask(host, ports, shuffle, parallelism, timeout);
    Future.delayed(Duration(seconds: 2), () {
      print('ScannerTask cancelled by timeout after ${stopwatch2.elapsed}');
      scannerTask1
          .cancel()
          .then((report) => print('Host ${report.host} scan was cancelled\n'
              'Scanned ports:\t${report.openPorts.length + report.closedPorts.length}\n'
              'Open ports:\t${report.openPorts}\n'
              'Closed ports:\t${report.closedPorts}\n'
              'Filtered ports:\t${report.filteredPorts}\n'
              'Status:\t${report.status}\n'
              'Elapsed:\t${stopwatch2.elapsed}\n'))
          .catchError((error) => stderr.writeln(error));
    });
    await scannerTask1.start();
  } catch (error) {
    stderr.writeln(error);
  }

  // 获取扫描期间的报告
  var stopwatch3 = Stopwatch()..start();
  try {
    print('Starting scan with periodic reports...');
    var scannerTask2 = scannerTask(host, ports, shuffle, parallelism, timeout);
    Timer.periodic(Duration(seconds: 1), (timer) async {
      try {
        var report = await scannerTask2.report;
        var percents = 100.0 *
            (report.openPorts.length + report.closedPorts.length) /
            report.ports.length;
        var scanned = report.closedPorts.length + report.openPorts.length;
        print('Host $host scan progress ${percents.toStringAsFixed(1)}%\n'
            'Scanned ports:\t$scanned of ${report.ports.length}\n'
            'Open ports:\t${report.openPorts}\n'
            'Closed ports:\t${report.closedPorts}\n'
            'Filtered ports:\t${report.filteredPorts}\n'
            'Status:\t${report.status}\n'
            'Elapsed:\t${stopwatch3.elapsed}\n');
        if (report.status == PortScannerTaskReportStatus.finished) {
          timer.cancel();
        }
      } catch (e) {
        stderr.writeln('Error retrieving report: $e');
        timer.cancel();
      }
    });
    await scannerTask2.start();
  } catch (error) {
    stderr.writeln(error);
  }
}

// 执行单个端口扫描任务
Future<void> _performSingleScan({
  required String host,
  required List<int> ports,
  required ScannerTask scannerTask,
  required bool shuffle,
  required int parallelism,
  required Duration timeout,
}) async {
  var stopwatch1 = Stopwatch()..start();

  // 简单扫描
  try {
    print('Starting simple scan...');
    await scannerTask(host, ports, shuffle, parallelism, timeout)
        .start()
        .then((report) {
      print('Host ${report.host} scan completed\n'
          'Scanned ports:\t${report.ports.length}\n'
          'Open ports:\t${report.openPorts}\n'
          'Closed ports:\t${report.closedPorts}\n'
          'Filtered ports:\t${report.filteredPorts}\n'
          'Status:\t${report.status}\n'
          'Elapsed:\t${stopwatch1.elapsed}\n');
    }).catchError((error) => stderr.writeln(error));
  } catch (e) {
    stderr.writeln('Error: $e');
  }

  // 通过延迟取消扫描
  var stopwatch2 = Stopwatch()..start();
  try {
    print('Starting scan with cancellation...');
    var scannerTask1 = scannerTask(host, ports, shuffle, parallelism, timeout);
    Future.delayed(Duration(seconds: 2), () {
      print('ScannerTask cancelled by timeout after ${stopwatch2.elapsed}');
      scannerTask1
          .cancel()
          .then((report) => print('Host ${report.host} scan was cancelled\n'
              'Scanned ports:\t${report.openPorts.length + report.closedPorts.length}\n'
              'Open ports:\t${report.openPorts}\n'
              'Closed ports:\t${report.closedPorts}\n'
              'Filtered ports:\t${report.filteredPorts}\n'
              'Status:\t${report.status}\n'
              'Elapsed:\t${stopwatch2.elapsed}\n'))
          .catchError((error) => stderr.writeln(error));
    });
    await scannerTask1.start();
  } catch (error) {
    stderr.writeln(error);
  }

  // 获取扫描期间的报告
  var stopwatch3 = Stopwatch()..start();
  try {
    print('Starting scan with periodic reports...');
    var scannerTask2 = scannerTask(host, ports, shuffle, parallelism, timeout);
    Timer.periodic(Duration(seconds: 1), (timer) async {
      try {
        var report = await scannerTask2.report;
        var percents = 100.0 *
            (report.openPorts.length + report.closedPorts.length) /
            report.ports.length;
        var scanned = report.closedPorts.length + report.openPorts.length;
        print('Host $host scan progress ${percents.toStringAsFixed(1)}%\n'
            'Scanned ports:\t$scanned of ${report.ports.length}\n'
            'Open ports:\t${report.openPorts}\n'
            'Closed ports:\t${report.closedPorts}\n'
            'Filtered ports:\t${report.filteredPorts}\n'
            'Status:\t${report.status}\n'
            'Elapsed:\t${stopwatch3.elapsed}\n');
        if (report.status == PortScannerTaskReportStatus.finished) {
          timer.cancel();
        }
      } catch (e) {
        stderr.writeln('Error retrieving report: $e');
        timer.cancel();
      }
    });
    await scannerTask2.start();
  } catch (error) {
    stderr.writeln(error);
  }
}

以上是 dart_port_scanner 插件的基本用法和完整示例代码。你可以根据需要调整参数和逻辑以满足具体需求。


更多关于Flutter端口扫描插件dart_port_scanner的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter端口扫描插件dart_port_scanner的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何使用Flutter端口扫描插件dart_port_scanner的示例代码。这个插件允许你在Flutter应用中执行端口扫描操作。

首先,确保你的Flutter项目已经添加了dart_port_scanner依赖。在pubspec.yaml文件中添加以下依赖:

dependencies:
  flutter:
    sdk: flutter
  dart_port_scanner: ^最新版本号  # 请替换为最新的版本号

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

接下来,编写Flutter代码来使用这个插件。以下是一个简单的示例,展示如何扫描指定IP地址上的端口范围:

import 'package:flutter/material.dart';
import 'package:dart_port_scanner/dart_port_scanner.dart';

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String result = "";

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Port Scanner Example'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              ElevatedButton(
                onPressed: _scanPorts,
                child: Text('Scan Ports'),
              ),
              Text(result, style: TextStyle(fontSize: 18)),
            ],
          ),
        ),
      ),
    );
  }

  Future<void> _scanPorts() async {
    String ipAddress = "192.168.1.1";  // 替换为你想要扫描的IP地址
    int startPort = 1;
    int endPort = 1024;

    setState(() {
      result = "Scanning ports...";
    });

    try {
      var scanner = PortScanner();
      var openPorts = await scanner.scan(ipAddress, startPort, endPort);

      setState(() {
        result = "Open ports:\n" + openPorts.join("\n");
      });
    } catch (e) {
      setState(() {
        result = "Error: ${e.message}";
      });
    }
  }
}

在这个示例中,我们创建了一个简单的Flutter应用,其中包含一个按钮和一个文本显示区域。当用户点击按钮时,应用会开始扫描指定IP地址(在示例中是192.168.1.1)上的端口范围(从1到1024)。扫描完成后,结果显示在文本区域中。

请注意:

  1. 权限:在真实应用中,特别是涉及到网络操作时,请确保你有适当的权限,尤其是在Android和iOS平台上。你可能需要在AndroidManifest.xmlInfo.plist中添加相应的权限声明。

  2. IP地址和端口范围:在示例中,IP地址和端口范围被硬编码了。在实际应用中,你可能希望让用户能够输入这些值。

  3. 错误处理:示例中包含了基本的错误处理,但在生产环境中,你可能需要更详细的错误处理和用户反馈机制。

  4. 性能考虑:端口扫描可能会比较耗时,特别是在扫描大量端口时。考虑在后台线程中执行扫描操作,以避免阻塞UI线程。

希望这个示例对你有帮助!如果有其他问题,请随时提问。

回到顶部