Flutter Mikrotik MNDP协议通信插件mikrotik_mndp的使用

Flutter Mikrotik MNDP协议通信插件mikrotik_mndp的使用

简介

这是用于通过MikroTik邻居发现协议(MNDP)发现网络设备的Flutter插件。

使用方法

pub package


要使用此插件,在`pubspec.yaml`文件中添加`mikrotik_mndp`作为依赖项。

该插件负责向网络上的MikroTik设备发送广播/多播请求。这些设备接收到请求后会响应其信息。然后插件解码响应并以流的形式发送一个`MndpMessage`对象。

`MndpMessage`对象包含以下字段:

| 字段               | 描述                         | 示例                       |
|--------------------|----------------------------|--------------------------|
| `type`             | 消息类型                     | 0                        |
| `ttl`              | 消息存活时间                 | 0                        |
| `sequence`         | 消息序列号                   | 7                        |
| `mac_address`      | 设备的MAC地址                | 48:8F:5A:AD:7E:E9        |
| `identity`         | 设备的身份                   | MikroTik                 |
| `version`          | 设备的软件版本               | 6.45.9 (长期支持版)       |
| `platform`         | 硬件平台                     | MikroTik                 |
| `uptime`           | 自上次重启以来的时间(秒)   | 201                      |
| `software_id`      | 软件标识符                   | H5ZN-JERX                |
| `board_name`       | 硬件型号名称                 | RB931-2nD                |
| `unpack`           | 消息解包状态                 | 0                        |
| `interface_name`   | 网络接口名称                 | bridgeLocal/ether2       |
| `unicast_ipv4_address` | 设备的单播IPv4地址        | 192.168.1.125            |

该插件还会根据设备名称搜索其附加信息(图像、商业名称、在MikroTik页面上的描述链接)。

### 示例

<img src="https://raw.githubusercontent.com/Eitol/mikrotik_mndp/main/doc/img.jpg" alt="App Example Screenshot">

```dart
import 'package:flutter/material.dart';
import 'package:mikrotik_mndp/decoder.dart';
import 'package:mikrotik_mndp/product_info_provider.dart';
import 'package:url_launcher/url_launcher.dart';
import 'message.dart';
import 'listener.dart';

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

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Mikrotik MNDP Demo',
      home: MyHomePage(title: 'Mikrotik MNDP Demo'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  final String title;

  const MyHomePage({super.key, required this.title});

  [@override](/user/override)
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final List<MndpMessage> _messages = [];

  [@override](/user/override)
  Widget build(BuildContext context) {
    var productProvider = MikrotikProductInfoProviderImpl();
    var decoder = MndpMessageDecoderImpl(productProvider);
    MNDPListener mndpListener = MNDPListener(decoder);
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: SingleChildScrollView(
        child: Column(      
          children: [
            StreamBuilder(
                stream: mndpListener.listen(),
                builder: (BuildContext context,
                    AsyncSnapshot<MndpMessage> snapshot) {
                  if (snapshot.hasData && snapshot.data != null) {
                    var found = false;
                    for (var i = 0; i < _messages.length; i++) {
                      if (_messages[i].macAddress ==
                          snapshot.data!.macAddress) {
                        _messages[i] = snapshot.data!;
                        found = true;
                        break;
                      }
                    }
                    if (!found) {
                      _messages.add(snapshot.data!);
                    }
                    return Column(
                      children: _messages
                          .map((message) => MndpMessageWidget(message: message))
                          .toList(),
                    );
                  }
                  return const Text('Awaiting MNDP messages...');
                }),
          ],
        ),
      ),
    );
  }
}

class MndpMessageWidget extends StatelessWidget {
  final MndpMessage message;

  const MndpMessageWidget({Key? key, required this.message}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Card(
      elevation: 4.0,
      child: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Visibility(
              visible: message.productInfo?.imageUrl != null,
              child: SizedBox(
                height: 200,
                child: Image.network(message.productInfo!.imageUrl),
              ),
            ),
            ListTile(
              title: Text(message.boardName ?? '未知'),
              subtitle: Text('MAC: ${message.macAddress ?? 'N/A'}'),
            ),
            _infoRow('商业名称', message.productInfo?.name ?? 'N/A'),
            _infoRow('板卡名称', message.boardName),
            _infoRow('MAC 地址', message.macAddress),
            _infoRow('身份', message.identity),
            _infoRow('IPv4 地址', message.unicastIpv4Address),
            _infoRow('IPv6 地址', message.unicastIpv6Address),
            _infoRow('版本', message.version),
            _infoRow('平台', message.platform),
            _infoRow('运行时间', _formatDuration(message.uptime)),
            _infoRow('软件ID', message.softwareId),
            InkWell(
              onTap: () async {
                var url = message.productInfo?.productUrl ?? '';
                var uri = Uri.parse(url);
                if (await canLaunchUrl(uri)) {
                  await launchUrl(uri, mode: LaunchMode.externalApplication);
                }
              },
              child: const Text(
                "页面链接",
                style: TextStyle(
                    color: Colors.blue, decoration: TextDecoration.underline),
              ),
            ),       
          ],
        ),
      ),
    );
  }

  Widget _infoRow(String label, String? value) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 4.0),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Text(label, style: const TextStyle(fontWeight: FontWeight.bold)),
          Text(value ?? 'N/A'),
        ],
      ),
    );
  }

  String _formatDuration(Duration? duration) {
    return duration != null
        ? '${duration.inHours}小时 ${duration.inMinutes % 60}分钟'
        : 'N/A';
  }
}

更多关于Flutter Mikrotik MNDP协议通信插件mikrotik_mndp的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter Mikrotik MNDP协议通信插件mikrotik_mndp的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


mikrotik_mndp 是一个用于与 MikroTik 设备进行 MNDP(MikroTik Neighbor Discovery Protocol)通信的 Flutter 插件。MNDP 协议允许设备在局域网内发现其他 MikroTik 设备,并获取其基本信息,如 IP 地址、MAC 地址、设备型号等。

以下是如何在 Flutter 项目中使用 mikrotik_mndp 插件的基本步骤:

1. 添加依赖

首先,你需要在 pubspec.yaml 文件中添加 mikrotik_mndp 插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  mikrotik_mndp: ^0.0.1  # 请确保使用最新版本

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

2. 初始化插件

在你的 Dart 代码中,导入 mikrotik_mndp 插件并初始化它:

import 'package:mikrotik_mndp/mikrotik_mndp.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MNDPExample(),
    );
  }
}

class MNDPExample extends StatefulWidget {
  @override
  _MNDPExampleState createState() => _MNDPExampleState();
}

class _MNDPExampleState extends State<MNDPExample> {
  final MikrotikMNDP _mndp = MikrotikMNDP();

  @override
  void initState() {
    super.initState();
    _startDiscovery();
  }

  void _startDiscovery() async {
    _mndp.startDiscovery().listen((device) {
      print('Discovered device: ${device.toMap()}');
    });
  }

  @override
  void dispose() {
    _mndp.stopDiscovery();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('MikroTik MNDP Example'),
      ),
      body: Center(
        child: Text('Discovering MikroTik devices...'),
      ),
    );
  }
}

3. 处理发现的设备

_mndp.startDiscovery() 返回一个 Stream,你可以监听这个流来获取发现的设备信息。每个设备信息是一个 MNDPDevice 对象,包含以下属性:

  • macAddress: 设备的 MAC 地址
  • identity: 设备的标识(通常为设备名称)
  • version: 设备的固件版本
  • platform: 设备的硬件平台
  • uptime: 设备的运行时间
  • softwareId: 设备的软件 ID
  • interfaceName: 设备的接口名称
  • unpack: 设备的 unpack 信息

你可以将这些信息显示在 UI 上,或者进行其他处理。

4. 停止发现

当你不再需要发现设备时,可以调用 _mndp.stopDiscovery() 来停止发现过程。

5. 注意事项

  • 确保你的应用有访问网络的权限。
  • MNDP 协议通常只在局域网内有效,因此你的设备和 MikroTik 设备需要在同一个局域网内。

6. 示例输出

当插件发现 MikroTik 设备时,你可能会看到类似以下的输出:

Discovered device: {macAddress: 00:0C:42:12:34:56, identity: MikroTik-Router, version: 6.47.7, platform: RB750Gr3, uptime: 123456, softwareId: 12345, interfaceName: ether1, unpack: ...}
回到顶部