Flutter JSON RPC通信插件general_json_rpc的使用

Flutter JSON RPC通信插件general_json_rpc的使用

GeneralJsonRpc

GeneralJsonRpc 是一个实现了 JSON-RPC v2.0 的包,其目的是简化通过网络调用方法和交换数据。

该包专注于将 JSON-RPC 消息编码和解码为字节,以便使用任何协议进行发送和接收。

快速指南

在这个指南中,你将创建一个服务器端和客户端应用程序,通过 TCP 套接字调用方法。

让我们开始:

  • 首先在服务器端我们定义了三个方法:sumprintquit

    • sum 方法接收数字列表并返回它们的总和。
    • print 方法接收一个名为 message 的参数并在服务器端打印其内容。
    • quit 方法通过执行 exit(0) 结束应用程序。
import 'dart:io';
import 'package:general_json_rpc/general_json_rpc.dart';

void main() {
  server();
  client();
}

服务器端代码

void server() async {
  final server = await ServerSocket.bind(InternetAddress.anyIPv4, 8081);
  print('[server] Server is running on port 8081');

  // 创建 MethodRunner 来定义 RPC 方法
  final runner = MethodRunner();

  // 现在定义三个方法
  runner.register<int>('sum', (numbers) => numbers.reduce((a, b) => a + b));
  runner.register<void>('print', (p) => print(p['message']));
  
  runner.register('quit', (_) {
    print('[server] Quit');
    exit(0);
  });

  // 现在监听新客户端
  await for (final Socket client in server) {
    print('[server] new client');
    client.listen(
      (bytes) async {
        // 将字节转换为 RpcObject
        final rpcObject = RpcObject.decode(bytes);

        // 处理不同的情况
        final response = await RpcObject.auto(rpcObject, methodRunner: runner);

        // 如果响应不为空,则将其转换为字节并发送给客户端
        if (response != null) client.add(response.encode());
      },
    );
  }
}

客户端代码

void client() async {
  print('[client] connecting...');
  final client = await Socket.connect(InternetAddress.loopbackIPv4, 8081);
  print('[client] connected!');

  // 创建控制器以帮助发送请求和响应
  final controller = RpcController();

  // 使用控制器发送请求和响应
  controller.sendEvent.addListener(
    // 在发送之前对 rpcMessage 进行编码
    (rpcMessage) => client.add(rpcMessage.encode()),
  );

  // 监听消息
  client.listen(
    (bytes) async {
      // 将字节转换为 RpcObject
      final rpcObject = RpcObject.decode(bytes);

      // 处理 rpcObject
      RpcObject.auto(rpcObject, controller: controller);
    },
  );

  // 现在首先请求 `sum` 方法
  // 我们将传递一个包含 1、2、3 的数字列表
  // sum 将返回 Future<int>
  // 可以通过监听 RpcError 来处理错误
  controller.request<int>('sum', [1, 2, 3]).then((result) {
    print('[client] sum result: $result');
  }).onError<RpcError>((error, _) {
    print('[client] error: ${error.message}');
  });

  // ============================= //
  // 现在调用 `print` 方法,不期望返回值
  controller.notify(
    'print',
    {
      'message': 'A message to be printed on the server side by the client',
    },
  );

  // ============================= //
  // 在 5 秒后关闭服务器,调用 `quit` 方法
  // 不期望返回值,因此我们将发送一个 RPC 通知
  await Future.delayed(
    const Duration(seconds: 5),
    () => controller.notify('quit'),
  );
}

完整示例代码

import 'dart:io';
import 'package:general_json_rpc/general_json_rpc.dart';

void main() async {
  server();
  client();
}

void server() async {
  final server = await ServerSocket.bind(InternetAddress.anyIPv4, 8081);
  print('[server] Server is running on port 8081');

  // 创建 MethodRunner 来定义 RPC 方法
  final runner = MethodRunner();

  // 现在定义三个方法
  runner.register<int>('sum', (numbers) => numbers.reduce((a, b) => a + b));
  runner.register<void>('print', (p) => print(p['message']));
  runner.register<void>('quit', (_) => exit(0));

  // 现在监听新客户端
  await for (final Socket client in server) {
    print('[server] new client');
    client.listen(
      (bytes) async {
        // 将字节转换为 RpcObject
        final rpcObject = RpcObject.decode(bytes);

        // 处理不同情况
        // 我们将处理请求和通知
        // 请求有返回值而通知没有
        // 我们将使用 [onRequestAll] 参数来处理两者
        // 我们将使用 runner.executeRequest 作为回调
        // handle 将返回一个 Future 的可空 RpcObject,这是当前请求的响应(如果有)
        final response = await RpcObject.handle(
          rpcObject,
          onRequestAll: runner.executeRequest,
        );

        // 如果响应不为空,则将其转换为字节并发送给客户端
        if (response != null) client.add(response.encode());
      },
    );
  }
}

void client() async {
  print('[client] connecting...');
  final client = await Socket.connect(InternetAddress.loopbackIPv4, 8081);
  print('[client] connected!');

  // 现在首先请求 `sum` 方法
  // 我们期望返回值
  // 因此我们将发送一个 RPC 请求
  // 我们将传递一个包含 1、2、3 的数字列表
  final request = RpcRequest.create('sum', [1, 2, 3]);

  // 现在将请求发送到服务器
  // 首先使用 `encode()` 方法进行编码然后发送
  client.add(request.encode());

  // ============================= //
  // 现在调用 `print` 方法
  // 我们不期望返回值
  // 因此我们将发送一个 RPC 通知
  final request2 = RpcRequest.notify('print', {});

  // 我创建了一个空的 Map 作为参数
  // 为了向你展示如何向请求添加额外的参数
  // 我将定义键 `message` 并添加我的消息
  request2['message'] =
      'A message to be printed on the server side by the client';

  // 现在编码并发送通知请求
  client.add(request2.encode());

  // ============================= //
  // 现在通过调用 `quit` 方法在 5 秒后关闭服务器
  // 我们不期望返回值
  // 因此我们将发送一个 RPC 通知
  client.add(RpcRequest.notify('quit').encode());
}

监听响应

首先,我们需要在客户端处理响应。

client.listen(
  (bytes) {
    final rpcObject = RpcObject.decode(bytes);

    RpcObject.handle(
      rpcObject,
      onResponse: RpcResponseManager.global.handleResponse,
    );
  },
);

现在我们在全局 RpcResponseManager 对象上监听并处理任何响应。

现在让我们处理 sum 方法的结果。

final request = RpcRequest.create('sum', [1, 2, 3]);

client.add(request.encode());

request.waitForResponse().then((result) {
    print('[client] sum result: $result');
  }).onError<RpcError>((error, _) {
    print('[client] error: ${error.message}');
  });

你也可以这样处理:

final sum = await request.waitForResponse();

不要忘记我们发送了一个 quit 方法的通知来结束应用。 但现在我们的应用需要等待结果返回,所以我们可以在接收结果后再发送它或注释掉它。

request.waitForResponse().then((result) {
    print('[client] sum result: $result');
    client.add(RpcRequest.notify('quit').encode());
  }).onError<RpcError>((error, _) {
    print('[client] error: ${error.message}');
  });

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

1 回复

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


general_json_rpc 是一个用于在 Flutter 中实现 JSON-RPC 通信的插件。JSON-RPC 是一种轻量级的远程过程调用 (RPC) 协议,它使用 JSON 格式来编码请求和响应。

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

1. 添加依赖

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

dependencies:
  flutter:
    sdk: flutter
  general_json_rpc: ^1.0.0  # 请使用最新版本

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

2. 创建 JSON-RPC 客户端

接下来,你可以创建一个 JSON-RPC 客户端来与服务器进行通信。

import 'package:general_json_rpc/general_json_rpc.dart';
import 'package:http/http.dart' as http;

class JsonRpcClient {
  final String url;
  final JsonRpcClientChannel channel;

  JsonRpcClient(this.url)
      : channel = JsonRpcClientChannel(url, httpClient: http.Client());

  Future<dynamic> call(String method, [dynamic params]) async {
    final response = await channel.sendRequest(method, params);
    return response.result;
  }
}

3. 使用 JSON-RPC 客户端进行通信

现在你可以使用 JsonRpcClient 来发送 JSON-RPC 请求并处理响应。

void main() async {
  final client = JsonRpcClient('https://example.com/jsonrpc');

  try {
    final result = await client.call('echo', {'message': 'Hello, JSON-RPC!'});
    print('Response: $result');
  } catch (e) {
    print('Error: $e');
  }
}

4. 处理错误

JSON-RPC 协议允许服务器返回错误响应。你可以通过捕获异常来处理这些错误。

void main() async {
  final client = JsonRpcClient('https://example.com/jsonrpc');

  try {
    final result = await client.call('nonexistent_method');
    print('Response: $result');
  } on JsonRpcError catch (e) {
    print('JSON-RPC Error: ${e.code} - ${e.message}');
  } catch (e) {
    print('Error: $e');
  }
}

5. 使用自定义 HTTP 客户端

如果你需要使用自定义的 HTTP 客户端(例如,处理认证或代理),你可以通过 httpClient 参数传递给 JsonRpcClientChannel

import 'package:http/http.dart' as http;

void main() async {
  final httpClient = http.Client();
  final client = JsonRpcClient('https://example.com/jsonrpc', httpClient: httpClient);

  try {
    final result = await client.call('echo', {'message': 'Hello, JSON-RPC!'});
    print('Response: $result');
  } catch (e) {
    print('Error: $e');
  } finally {
    httpClient.close();
  }
}

6. 处理批量请求

general_json_rpc 还支持批量请求,你可以一次性发送多个请求并接收多个响应。

void main() async {
  final client = JsonRpcClient('https://example.com/jsonrpc');

  try {
    final responses = await client.channel.sendBatch([
      JsonRpcRequest(method: 'echo', params: {'message': 'Hello, JSON-RPC!'}),
      JsonRpcRequest(method: 'add', params: [1, 2]),
    ]);

    for (var response in responses) {
      print('Response: ${response.result}');
    }
  } catch (e) {
    print('Error: $e');
  }
}

7. 处理通知

JSON-RPC 还支持通知(即不需要响应的请求)。你可以使用 sendNotification 方法来发送通知。

void main() async {
  final client = JsonRpcClient('https://example.com/jsonrpc');

  try {
    await client.channel.sendNotification('notify', {'message': 'Hello, JSON-RPC!'});
    print('Notification sent');
  } catch (e) {
    print('Error: $e');
  }
}
回到顶部