Flutter进程间通信插件dart_ipc的使用

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

Flutter进程间通信插件dart_ipc的使用

dart_ipc简介

dart_ipc 是一个跨平台的 Dart 进程间通信(IPC)库,利用本地平台机制在进程之间提供高效的通信。它支持 Windows、Linux、macOS 和 Android 平台。

特性

  • 跨平台:适用于 Windows、Linux、macOS 和 Android。
  • 原生性能:在 Windows 上使用 Named pipe,在 Unix 系统上使用 Unix domain socket
  • 简单API:与 socket API 兼容。

安装

要安装 dart_ipc 插件,请在终端中运行以下命令:

dart pub add dart_ipc

使用示例

服务器端代码示例
import 'package:dart_ipc/dart_ipc.dart';

final serverSocket = await bind(path);

await for (final socket in serverSocket) {
  print(socket);
  socket.listen((data) {
    // 打印接收到的数据
    print(utf8.decode(data));
    // 发送数据到客户端
    socket.add(utf8.encode('Hello from Server'));
  }, onDone: () {
    print("Server Done");
  }, onError: (e) {
    print("Server Error: $e");
  });
}
客户端代码示例
import 'package:dart_ipc/dart_ipc.dart';

final socket = await connect(path);

socket.listen((data) {
  // 打印接收到的数据
  print(utf8.decode(data));
}, onDone: () {
  print("Client Done");
}, onError: (e) {
  print("Client Error: $e");
});

for (var i = 0; i < 10; i++) {
  // 发送数据到服务器
  socket.add(utf8.encode("Hello from client2 $i"));
  await Future.delayed(Duration(seconds: 1));
}
await socket.close();
JSON-RPC 集成示例
服务器端代码
import 'package:dart_ipc/dart_ipc.dart';
import 'package:json_rpc_2/json_rpc_2.dart';
import 'package:web_socket_channel/io.dart';
import 'package:web_socket_channel/web_socket_channel.dart';

void main() async {
  final serverSocket = await bind(path);
  final httpServer = HttpServer.listenOn(serverSocket);
  final connectedChannels = httpServer
      .transform(WebSocketTransformer())
      .map(IOWebSocketChannel.new);
  connectedChannels.listen(handleClient);
}

void handleClient(WebSocketChannel socket) {
  var server = Server(socket.cast<String>());

  var i = 0;
  server.registerMethod('count', () {
    return i++;
  });

  server.registerMethod('echo', (Parameters params) {
    return params['message'].value;
  });

  server.registerMethod('subtract', (Parameters params) {
    return params['minuend'].asNum - params['subtrahend'].asNum;
  });

  server.registerMethod('sort', (Parameters params) {
    var list = params['list'].asList;
    list.sort();
    if (params['descendint'].asBoolOr(false)) {
      return list.reversed;
    } else {
      return list;
    }
  });

  const divideByZero = 1;
  server.registerMethod('divide', (Parameters params) {
    var divisor = params['divisor'].asNum;
    if (divisor == 0) {
      throw RpcException(divideByZero, 'Cannot divide by zero.');
    }

    return params['dividend'].asNum / divisor;
  });

  server.listen();
}
客户端代码
import 'package:dart_ipc/dart_ipc.dart';
import 'package:json_rpc_2/json_rpc_2.dart';
import 'package:web_socket_channel/io.dart';
import 'package:web_socket_channel/web_socket_channel.dart';

void main() async {
  final httpClient = HttpClient()
    ..connectionFactory =
        (Uri uri, String? proxyHost, int? proxyPort) {
      final socket = connect(path);
      return Future.value(
          ConnectionTask.fromSocket(socket, () {}));
    };

  final socket = IOWebSocketChannel.connect("ws://localhost",
      customClient: httpClient);
  var client = Client(socket.cast<String>());

  unawaited(client.listen());

  var count = await client.sendRequest('count');
  print('Count is $count');

  var echo =
      await client.sendRequest('echo', {'message': 'hello'});
  print('Echo says "$echo"!');

  client.sendNotification('count');

  try {
    await client
        .sendRequest('divide', {'dividend': 2, 'divisor': 0});
  } on RpcException catch (error) {
    print('RPC error ${error.code}: ${error.message}');
  }
}

平台支持

平台 实现
Windows Named pipe
Linux Unix domain socket
macOS Unix domain socket
Android Unix domain socket

许可证

该项目采用 MIT 许可证 - 查看 LICENSE 文件了解详情。

完整示例 Demo

以下是完整的 Flutter 应用程序示例,包含服务器和客户端功能:

import 'dart:convert';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:path/path.dart' as path;
import 'dart:async';

import 'package:dart_ipc/dart_ipc.dart';
import 'package:path_provider/path_provider.dart';

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

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

  [@override](/user/override)
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  late String _path;

  [@override](/user/override)
  void initState() {
    super.initState();

    if (Platform.isWindows) {
      _path = r"\\.\pipe\dart_ipc";
    } else {
      (() async {
        _path =
            path.join((await getTemporaryDirectory()).path, "dart_ipc.unix");
      })();
    }
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin example app'),
        ),
        body: Center(
          child: Row(
            children: [
              TextButton(
                  onPressed: () async {
                    final serverSocket = await bind(_path);

                    await for (final socket in serverSocket) {
                      print(socket);
                      socket.listen((data) {
                        print(utf8.decode(data));
                        socket.add(utf8.encode('Hello from Server'));
                      }, onDone: () {
                        print("Server Done");
                      }, onError: (e) {
                        print("Server Error: $e");
                      });
                    }
                  },
                  child: Text("Server")),
              TextButton(
                  onPressed: () async {
                    final socket = await connect(_path);

                    socket.listen((data) {
                      print(utf8.decode(data));
                    }, onDone: () {
                      print("Client Done");
                    }, onError: (e) {
                      print("Client Error: $e");
                    });

                    for (var i = 0; i < 10; i++) {
                      socket.add(utf8.encode("Hello from client1 $i"));
                      await Future.delayed(Duration(seconds: 1));
                    }
                    await socket.close();
                  },
                  child: Text("Client1")),
              TextButton(
                  onPressed: () async {
                    final socket = await connect(_path);

                    socket.listen((data) {
                      print(utf8.decode(data));
                    }, onDone: () {
                      print("Client Done");
                    }, onError: (e) {
                      print("Client Error: $e");
                    });

                    for (var i = 0; i < 10; i++) {
                      socket.add(utf8.encode("Hello from client2 $i"));
                      await Future.delayed(Duration(seconds: 1));
                    }
                    await socket.close();
                  },
                  child: Text("Client2")),
            ],
          ),
        ),
      ),
    );
  }
}

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

1 回复

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


当然,以下是一个关于如何在Flutter项目中使用dart_ipc插件来实现进程间通信(IPC)的代码示例。dart_ipc插件允许你在Flutter应用的不同隔离环境中进行通信,比如在不同的isolate之间。

首先,确保你已经在pubspec.yaml文件中添加了dart_ipc依赖:

dependencies:
  flutter:
    sdk: flutter
  dart_ipc: ^最新版本号 # 请替换为当前最新版本号

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

示例代码

主应用代码(main.dart)

import 'package:flutter/material.dart';
import 'package:dart_ipc/dart_ipc.dart';
import 'dart:isolate';

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

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

class _MyAppState extends State<MyApp> {
  static const platform = MethodChannel('com.example.myapp/channel');
  IpcReceiver? receiver;
  late IpcSender sender;

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

    // 启动一个Isolate并传递IpcSender
    Isolate.spawn(entryPoint, null, onExit: _onIsolateExit)
      .then((isolate) {
        sender = IpcSender(isolate);
      });

    // 初始化IpcReceiver以监听来自Isolate的消息
    receiver = IpcReceiver((message) {
      print('Received message from isolate: $message');
    });
  }

  @override
  void dispose() {
    receiver?.close();
    super.dispose();
  }

  void _onIsolateExit(Isolate isolate, {int? exitCode, String? reason}) {
    print('Isolate exited: $reason');
  }

  void sendMessageToIsolate(String message) {
    sender.send(message);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter IPC Demo'),
        ),
        body: Center(
          child: ElevatedButton(
            onPressed: () {
              sendMessageToIsolate('Hello from main isolate!');
            },
            child: Text('Send Message'),
          ),
        ),
      ),
    );
  }

  // Isolate的入口点
  static void entryPoint(dynamic message) async {
    IpcReceiver receiver = IpcReceiver((message) {
      print('Received message from main: $message');
      // 回复主Isolate
      IpcSender.current!.send('Hello from secondary isolate!');
    });

    // 保持Isolate活跃以监听消息
    await Future.delayed(Duration(days: 365));
  }
}

解释

  1. 依赖添加:确保在pubspec.yaml中添加了dart_ipc依赖。

  2. 主Isolate

    • 初始化IpcReceiver来监听来自其他Isolate的消息。
    • 使用Isolate.spawn启动一个新的Isolate,并传递一个IpcSender实例,以便主Isolate可以向新Isolate发送消息。
  3. 新Isolate

    • entryPoint函数中,初始化一个IpcReceiver来监听来自主Isolate的消息。
    • 使用IpcSender.current!发送回复消息给主Isolate。注意,IpcSender.current只能在被dart_ipc插件初始化的Isolate中使用。
  4. 消息发送

    • 在主Isolate中,点击按钮时通过sender.send(message)发送消息到新Isolate。
    • 在新Isolate中,接收到消息后,通过IpcSender.current!.send(message)回复消息给主Isolate。
  5. 资源管理

    • dispose方法中关闭IpcReceiver以释放资源。

通过上述代码,你可以在Flutter应用中实现基本的进程间通信。请注意,dart_ipc主要用于Dart isolates之间的通信,而不是操作系统级别的进程间通信。如果你需要进行跨操作系统的进程间通信,可能需要考虑其他方法或插件。

回到顶部