Flutter 开发windows应用-IP存活检测

1,056 阅读3分钟

因为工作上的一些需要,需要对局域网里的主机进行存活扫描,而且还要定时的扫一段时间,比如一个星期(难免在你扫的时候,刚好有些机器没有开机),统计存活次数。

一直没有怎么开发过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来实现了。

咬咬牙,请白老板出来镇楼,准备开饭.....

捕获1.PNG

第二步:确定核心技术解决方案

先说明一下需求,允许用户输入一个IP地址段,点击一下开始,就可以启动扫描。累计扫描次数。

捕获2.PNG

这就涉及到一个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

感觉打包后这个体积还是很不错的。

捕获3.PNG

待解决问题:

1、调用系统Ping会弹出 cmd窗口,还没查到怎么消除它。

捕获4.PNG

2、时间有限,接下来有时间再添加多线程提升速度。

3、加上定时器

4、设置为后台程序,放在后台跑

项目完整代码: github.com/yeelone/flu…

捕获5.PNG

个人主页: YEE领域

背单词Flutter APP: 领域英语APP