Flutter网络扫描插件tcp_scanner的使用
Flutter网络扫描插件tcp_scanner的使用
Simple and fast TCP scanner.
Usage
TcpScannerTask
TcpScannerTask allows you to execute scanning tasks asynchronously and provides basic methods to control task.
You can set shuffle
to true if you need to shuffle ports. By default, socket connect timeout is 2 seconds.
After this time the port will be marked as closed
if the response wouldn’t receive.
You may change this value by setting socketTimeout
option. By default socketTimeout
equals to 100 ms. You can specify the number of isolates to scan by
defining parallelism
option. By default, parallelism equals 4.
To execute simple task use start method and wait for result.
final host = '192.168.88.229';
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'))
// Catch errors during the scan
.catchError((error) => stderr.writeln(error));
} catch (e) {
// Here you can catch exceptions threw in the constructor
stderr.writeln('Error: $e');
}
Task can be cancelled using cancel()
method. It returns a Future with the result of the scan.
The cancel
method can throw TcpScannerTaskException
if task had already finished.
Pay attention that in case of cancelling a Future from the start()
method won’t be returned.
For example, if you will use await scannerTask.start()
you will never get the result.
var ports = List.generate(65535, (i) => 0 + i);
var stopwatch2 = Stopwatch();
stopwatch2.start();
try {
var scannerTask1 = TcpScannerTask(host, ports);
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'
'Status:\t${report.status}\n'
'Elapsed:\t${stopwatch2.elapsed}\n'))
.catchError((error) => stderr.writeln(error));
});
scannerTask1.start();
} catch (error) {
stderr.writeln(error);
}
You can request a status during the scanning using the report
field:
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 == TcpScannerTaskReportStatus.finished) {
timer.cancel();
}
});
});
await scannerTask2.start();
} catch (error) {
stderr.writeln(error);
}
TCPScanner
This class is deprecated, and it is highly recommended to use TcpScannerTask instead of TCPScanner.
It’s easy to scan a host. You just need to create the TCPScanner
instance and call scan
method. The result is stored in ScanResult
data object.
Scan specified ports:
import 'package:tcp_scanner/tcp_scanner.dart';
main() {
TCPScanner("localhost", [ 80, 8080, 443 ]).scan().then((result) {
print('''
HTTP ports scan result
Host: ${result.host}
Scanned ports: ${result.ports}
Open ports: ${result.open}
Closed ports: ${result.closed}
Elapsed time: ${result.elapsed / 1000}s
''');
});
}
If host is reachable and ports are closed output will be:
HTTP ports scan result
Host: localhost
Scanned ports: [80, 8080, 443]
Open ports: []
Closed ports: [80, 8080, 443]
Elapsed time: 0.03s
Sometimes you can not get response from the host or from specified port because of firewall or IDS. In this case port will be marked as closed
. To define connection establishment timeout you should use timeout
argumnet in the constructor. By default, timeout is 100ms.
Scan in the following example elapsed about 900 ms because it was scanned 3 ports of the unreachable host with 300ms timeout.
import 'package:tcp_scanner/tcp_scanner.dart';
main() {
TCPScanner(
"192.168.1.1",
[
80,
8080,
443
],
timeout: 100)
.scan()
.then((result) {
print('''
HTTP ports scan result
Host: ${result.host}
Scanned ports: ${result.ports}
Open ports: ${result.open}
Closed ports: ${result.closed}
Elapsed time: ${result.elapsed / 1000}s
''');
});
}
Output:
HTTP ports scan result
Host: 192.168.1.1
Scanned ports: [80, 8080, 443]
Open ports: []
Closed ports: [80, 8080, 443]
Elapsed time: 1.016s
You can use TCPScanner.range
constructor if you want to scan ports range:
import 'package:tcp_scanner/tcp_scanner.dart';
main() {
TCPScanner.range("127.0.0.1", 20, 1000).scan().then((result) {
print('''
20-1000 ports scan result
Host: ${result.host}
Scanned ports: 20-1000
Open ports: ${result.open}
Elapsed time: ${result.elapsed / 1000}s
''');
});
}
You can get the current status while scan is running. Just use TCPScanner.scanResult
to get current status. You can control update interval by updateInterval
parameter. By default, update interval is 1 second. Getting information about running scan:
import 'dart:async';
import 'package:tcp_scanner/tcp_scanner.dart';
main() {
var tcpScanner = TCPScanner.range("127.0.0.1", 20, 50000, updateInterval: Duration(seconds: 5));
var timer = Timer.periodic(Duration(seconds: 1), (timer) {
var scanProgress = 100.0 * (tcpScanner.scanResult.scanned.length / tcpScanner.scanResult.ports.length);
print("Progress ${scanProgress.toStringAsPrecision(3)}%");
});
tcpScanner.scan().then((result) {
timer.cancel();
print('''
20-50000 ports scan result
Host: ${result.host}
Scanned ports: 20-50000
Open ports: ${result.open}
Elapsed time: ${result.elapsed / 1000}s
''');
});
}
Output:
Progress 0.00%
Progress 7.99%
Progress 18.2%
Progress 28.2%
Progress 38.2%
Progress 48.8%
Progress 59.6%
Progress 70.4%
Progress 81.1%
20-50000 ports scan result
Host: 127.0.0.1
Scanned ports: 20-50000
Open ports: [1024, 1025, 1026, 1027, 1028, 1029, 29754]
Elapsed time: 9.841s
You can improve perfomance by set isolates
argument. Also, you can shuffle ports using shuffle
option.
var multithreadedScanner = TCPScanner.range("127.0.0.1", 20, 5000, isolates: 10, shuffle: true);
var multithreadedTimer = Timer.periodic(Duration(seconds: 1), (timer) {
var scanProgress = 100.0 * (multithreadedScanner.scanResult.scanned.length / multithreadedScanner.scanResult.ports.length);
print("Progress ${scanProgress.toStringAsPrecision(3)}%");
});
multithreadedScanner.scan().then((result) {
multithreadedTimer.cancel();
print('''
20-5000 ports scan result
Host: ${result.host}
Scanned ports: 20-5000
Open ports: ${result.open}
Elapsed time: ${result.elapsed / 1000}s
''');
});
Open ports is shuffled in the report because shuffle
option was used and ports were scanned in a random order. Ports will be shuffled each call of scan()
.
Progress 0.00%
Progress 21.5%
Progress 52.4%
20-50000 ports scan result
Host: 127.0.0.1
Scanned ports: 20-50000
Open ports: [1028, 1029, 1024, 1027, 29754, 1026, 1025]
Elapsed time: 3.535s
Features and bugs
Please file feature requests and bugs at the issue tracker.
更多关于Flutter网络扫描插件tcp_scanner的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter网络扫描插件tcp_scanner的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,我可以为你提供一个关于如何在Flutter项目中使用tcp_scanner
插件来进行网络扫描的示例。tcp_scanner
插件允许你扫描开放的网络端口,这对于网络诊断和安全测试非常有用。
首先,你需要确保在pubspec.yaml
文件中添加了tcp_scanner
依赖项:
dependencies:
flutter:
sdk: flutter
tcp_scanner: ^0.0.4 # 请检查最新版本号
然后,运行flutter pub get
来安装依赖项。
接下来,我们可以创建一个简单的Flutter应用来演示如何使用tcp_scanner
插件。
示例代码
main.dart
import 'package:flutter/material.dart';
import 'package:tcp_scanner/tcp_scanner.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'TCP Scanner Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String result = "";
void scanNetwork(String ip, int startPort, int endPort) async {
setState(() {
result = "Scanning...";
});
try {
List<int> openPorts = await TcpScanner.scan(ip, startPort, endPort);
setState(() {
result = "Open Ports: ${openPorts.join(", ")}";
});
} catch (e) {
setState(() {
result = "Error: ${e.toString()}";
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('TCP Scanner Demo'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
TextField(
decoration: InputDecoration(
labelText: 'IP Address',
border: OutlineInputBorder(),
),
keyboardType: TextInputType.text,
textInputAction: TextInputAction.next,
onEditingComplete: () => FocusScope.of(context).requestFocus(focusNodePortStart),
),
SizedBox(height: 16),
TextField(
decoration: InputDecoration(
labelText: 'Start Port',
border: OutlineInputBorder(),
),
keyboardType: TextInputType.number,
textInputAction: TextInputAction.next,
controller: TextEditingController()..text = "1",
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
focusNode: FocusNode()..requestFocus(),
onEditingComplete: () => FocusScope.of(context).requestFocus(focusNodePortEnd),
),
SizedBox(height: 16),
TextField(
decoration: InputDecoration(
labelText: 'End Port',
border: OutlineInputBorder(),
),
keyboardType: TextInputType.number,
textInputAction: TextInputAction.done,
controller: TextEditingController()..text = "1024",
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
focusNode: FocusNode()..also((focusNodePortEnd) {
this.focusNodePortEnd = focusNodePortEnd;
}),
),
SizedBox(height: 32),
ElevatedButton(
onPressed: () {
String ip = (context.read<MyTextEditingController>().ipController.text).trim();
int startPort = int.parse((context.read<MyTextEditingController>().startPortController.text).trim());
int endPort = int.parse((context.read<MyTextEditingController>().endPortController.text).trim());
if (ip.isNotEmpty && startPort <= endPort) {
scanNetwork(ip, startPort, endPort);
} else {
setState(() {
result = "Invalid input. Please enter a valid IP and ensure start port is less than or equal to end port.";
});
}
},
child: Text('Scan'),
),
SizedBox(height: 32),
Text(result),
],
),
),
);
}
}
// 这是一个简单的依赖注入类,用于管理TextField控制器
class MyTextEditingController {
final TextEditingController ipController = TextEditingController();
final TextEditingController startPortController = TextEditingController();
final TextEditingController endPortController = TextEditingController();
}
// 使用Provider进行依赖注入(可选,根据需求使用)
// import 'package:provider/provider.dart';
// void main() {
// runApp(
// MultiProvider(
// providers: [
// Provider<MyTextEditingController>(create: (_) => MyTextEditingController()),
// ],
// child: MyApp(),
// ),
// );
// }
注意事项
- 权限问题:在某些平台上(如Android),你可能需要在
AndroidManifest.xml
中请求网络权限。
<uses-permission android:name="android.permission.INTERNET"/>
-
版本兼容性:确保你使用的
tcp_scanner
插件版本与你的Flutter SDK版本兼容。 -
错误处理:在实际应用中,你可能需要更详细的错误处理机制,比如处理网络错误、输入错误等。
-
依赖注入:上述代码示例中使用了简单的控制器管理类
MyTextEditingController
。如果你的项目结构更复杂,可以考虑使用依赖注入框架如Provider、Riverpod或GetX来管理状态。
这个示例展示了如何使用tcp_scanner
插件进行基本的网络端口扫描。你可以根据实际需求进一步扩展和优化这个示例。