因为工作上的一些需要,需要对局域网里的主机进行存活扫描,而且还要定时的扫一段时间,比如一个星期(难免在你扫的时候,刚好有些机器没有开机),统计存活次数。
一直没有怎么开发过windows应用,感觉这就是个日落西山的开发路线,没什么兴趣。不过自从Flutter 2.0 正式支持windows之后 ,突然有兴趣想试一下。就拿这个简单的IP扫描来练练手。
前情提要: 本项目只是为了体验Flutter 对windows的支持情况,代码随便拼拼凑凑,没有太过细究,请各位莫笑话。
第一步: Dart 对windows 的支持情况
IP检测,无非就是用Ping . 经过搜索,发现Dart有个包,Dart_ping , 但是最终试验结果是放弃了,不太准确,有错漏,跟我在网上下载的扫描工具一样,总有一些IP扫描不出来。
所以使用调用平台命令的方法,Dart有Process.run, 可以调用系统命令,使用方法如下 :
result = await Process.run("ping", [ip]);
嗯,Dart可以调用系统命令,那这个功能就确定可以用Flutter来实现了。
咬咬牙,请白老板出来镇楼,准备开饭.....
第二步:确定核心技术解决方案
先说明一下需求,允许用户输入一个IP地址段,点击一下开始,就可以启动扫描。累计扫描次数。
这就涉及到一个IP地址计算的问题,以下是代码:
1、解决IP地址运算的问题
// 将IP转为十进制
num ip2decimalism(
String field1, String field2, String field3, String field4) {
num ipnum1 = pow(2, 24) * int.parse(field1);
num ipnum2 = pow(2, 16) * int.parse(field2);
num ipnum3 = pow(2, 8) * int.parse(field3);
num ipnum4 = pow(2, 0) * int.parse(field4);
return ipnum1 + ipnum2 + ipnum3 + ipnum4;
}
// 将十进制转为IP
String decimalism2ip(int ipnum) {
String field1 = (ipnum >> 24).toString();
ipnum = ipnum - (pow(2, 24) * int.parse(field1)).toInt();
String field2 = (ipnum >> 16).toString();
ipnum = ipnum - (pow(2, 16) * int.parse(field2)).toInt();
String field3 = (ipnum >> 8).toString();
ipnum = ipnum - (pow(2, 8) * int.parse(field3)).toInt();
String field4 = ipnum.toString();
return field1 + "." + field2 + "." + field3 + "." + field4;
}
2、解决存储方案的问题
至于存储,没有必要太复杂 ,就使用了csv文件来保存。Dart对csv的读写代码如下:
getList() async {
final directory = await getApplicationDocumentsDirectory();
final pathOfTheFileToWrite = directory.path + "\\ipscan.csv";
File file = new File(pathOfTheFileToWrite);
try {
String content = await file.readAsString();
List<List<dynamic>> list = CsvToListConverter().convert(content);
for (var i = 0; i < list.length; i++) {
history[list[i][0]] = list[i][1];
lineMap[list[i][0]] = i;
_remarkControllers.add(new TextEditingController(text: list[i][3]));
}
scanResult = list;
} catch (e) {
print(e);
}
}
save() async {
final directory = await getApplicationDocumentsDirectory();
final pathOfTheFileToWrite = directory.path + "\\ipscan.csv";
for ( var i = 0 ; i < scanResult.length; i++) {
scanResult[i][3] = _remarkControllers[i].text;
}
String csv = const ListToCsvConverter().convert(scanResult);
File file = File(pathOfTheFileToWrite);
file.writeAsString(csv);
}
第三步,核心函数
startScan2() async {
ProcessResult result;
if (Platform.isWindows) {
// 起始值
num startIP = ip2decimalism(_controller1.text, _controller2.text,
_controller3.text, _controller4.text);
num endIP = ip2decimalism(_controller5.text, _controller6.text,
_controller7.text, _controller8.text);
int index = 0;
while (startIP <= endIP) {
String ip = decimalism2ip(startIP.toInt());
setState(() {
scanIP = "正在扫描" + ip + "...";
});
result = await Process.run("ping", [ip]);
var data = result.stdout.toString();
List<dynamic> line = [];
if (data.contains("TTL=")) {
// 证明能通
num? count = history[ip];
if (count == null) count = 0;
line = [
ip,
count + 1,
DateTime.now().year.toString() +
"-" +
DateTime.now().month.toString() +
"-" +
DateTime.now().day.toString(),
"无"
];
} else {
if (history.containsKey(ip)) {
num? count = history[ip];
if (count == null) count = 0;
line = [ip, count, "", "无"];
} else {
line = [ip, 0, "", "无"];
}
}
setState(() {
scanIP = "扫描结束 :" + ip + "\n" + line.toString();
});
if (lineMap.containsKey(ip)) {
// 已存在则更新
num? index = lineMap[ip];
scanResult[index!.toInt()] = line;
} else {
scanResult.add(line);
lineMap[ip] = scanResult.length - 1 ;
_remarkControllers.add(new TextEditingController(text: "无"));
}
index++;
startIP++;
}
save();
}
}
第四步:打包
$ flutter build windows
生成文件目标文件夹 E:\project\ipscan\build\windows\runner
感觉打包后这个体积还是很不错的。
待解决问题:
1、调用系统Ping会弹出 cmd窗口,还没查到怎么消除它。
2、时间有限,接下来有时间再添加多线程提升速度。
3、加上定时器
4、设置为后台程序,放在后台跑
项目完整代码: github.com/yeelone/flu…
个人主页: YEE领域
背单词Flutter APP: 领域英语APP