欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

前言

在现代软件架构中,RPC (Remote Procedure Call) 无处不在。它允许我们像调用本地函数一样调用远程服务器上的函数。虽然 gRPC 和 REST (HTTP/JSON) 十分流行,但在一些特定场景下,JSON-RPC 2.0 依然是不可替代的标准。

  • 轻量级:仅依赖 JSON,无须复杂的 Protobuf 编解码或 HTTP Header 开销。
  • 传输无关:可以跑在 WebSocket、TCP Socket、甚至串口(Serial Port)上。
  • 广泛支持:以太坊(Ethereum)、比特币(Bitcoin)节点通信全部基于 JSON-RPC。
  • 简单明了:人眼可读,调试极其方便。

json_rpc_2 是 Google 官方维护的一个 Dart 库,严格遵循 JSON-RPC 2.0 规范,提供了极高质量的 Client 和 Server 实现。

对于 OpenHarmony 开发者,这意味着你可以轻松地用 Dart 构建与底层硬件(如智能家居网关、工控机)通信的客户端,或者搭建一个极简的微服务 API。

一、核心原理与协议规范

1.1 JSON-RPC 2.0 协议详解

JSON-RPC 的消息体极其简洁。

请求 (Request)

{
  "jsonrpc": "2.0",
  "method": "subtract",
  "params": [42, 23], 
  "id": 1
}

响应 (Response)

{
  "jsonrpc": "2.0",
  "result": 19,
  "id": 1
}

通知 (Notification)
没有 id 字段,服务端收到后不返回任何结果(Fire-and-Forget)。

{
  "jsonrpc": "2.0",
  "method": "update",
  "params": [1, 2, 3, 4, 5]
}

错误 (Error)

{
  "jsonrpc": "2.0",
  "error": {
    "code": -32601,
    "message": "Method not found"
  },
  "id": "1"
}

json_rpc_2 库完全封装了这些 JSON 细节,让你直接面对 Dart 对象编程。

调用方法 add

序列化

网络传输 TCP/WS

逻辑处理

响应 JSON

返回 Future/结果

Flutter 客户端

json_rpc_2 库

请求明文

服务端

计算结果

二、核心 API 详解

2.1 客户端 (Client)

客户端需要一个 StreamChannel 来传输数据。这个 Channel 可以来自 web_socket_channel(用于 Web),也可以来自 dart:ioSocket(用于 TCP)。

import 'package:json_rpc_2/json_rpc_2.dart';
import 'package:web_socket_channel/io.dart';

void main() async {
  // 1. 建立连接
  var socket = IOWebSocketChannel.connect('ws://localhost:4321');
  
  // 2. 创建 Client
  var client = Client(socket.cast());
  
  // 3. 必须先 listen (启动消息循环)
  unawaited(client.listen()); 

  try {
    // 4. 发送请求
    var result = await client.sendRequest('add', [1, 2]);
    print('1 + 2 = $result');
    
    // 5. 发送通知 (无返回值)
    client.sendNotification('log', ['Connection established']);
  } finally {
    await client.close();
  }
}

在这里插入图片描述

2.2 服务端 (Server)

服务端 API 同样简洁。你可以注册方法来处理请求。

import 'package:json_rpc_2/json_rpc_2.dart';
import 'package:shelf/shelf_io.dart' as io;
import 'package:shelf_web_socket/shelf_web_socket.dart';

void main() {
  var handler = webSocketHandler((webSocket) {
    var server = Server(webSocket.cast());

    // 注册方法
    server.registerMethod('add', (Parameters params) {
      var nums = params.asList; 
      return nums[0] + nums[1];
    });

    server.registerMethod('subtract', (Parameters params) {
      var nums = params.asList;
      return nums[0] - nums[1];
    });

    // 启动监听
    server.listen();
  });

  io.serve(handler, 'localhost', 4321).then((server) {
    print('Serving at ws://${server.address.host}:${server.port}');
  });
}

2.3 错误处理

json_rpc_2 会自动抛出 RpcException。你可以捕获具体的错误码。

try {
  await client.sendRequest('unknown_method');
} on RpcException catch (e) {
  if (e.code == RpcException.methodNotFound) {
    print('Method not found!'); // Code -32601
  } else {
    print('Error ${e.code}: ${e.message}');
  }
}

在这里插入图片描述

三、OpenHarmony 平台适配实战

在鸿蒙系统(尤其是 IoT 设备)中,TCP 通信比 HTTP 更常见且更高效。我们可以使用 Dart 原生的 Socket 来承载 JSON-RPC。

3.1 基于 TCP Socket 的全双工通信

假设我们有一个运行在鸿蒙开发板上的 Dart 服务端,控制 LED 灯。

// lib/rpc_server.dart (运行在开发板)
import 'dart:io';
import 'package:json_rpc_2/json_rpc_2.dart';
import 'package:stream_channel/stream_channel.dart';

void startServer() async {
  // 监听 8080 端口
  var serverSocket = await ServerSocket.bind(InternetAddress.anyIPv4, 8080);
  print('Listening on port 8080...');

  await for (var socket in serverSocket) {
    // 将 Socket 包装为 StreamChannel<String> (UTF-8)
    var channel = jsonDocument.bind(
      StreamChannel(socket, socket)
    );
    
    var rpcServer = Server(channel);
    
    // 注册控制方法
    rpcServer.registerMethod('set_led', (Parameters params) {
      bool on = params['on'].asBool; // 获取命名参数
      print('Turning LED ${on ? 'ON' : 'OFF'}');
      // 硬件操作逻辑: GPIO.output(1, on);
      return {'status': 'ok', 'led': on};
    });

    rpcServer.listen();
  }
}

3.2 客户端控制 App (Flutter)

// lib/rpc_client.dart
import 'dart:io';
import 'package:json_rpc_2/json_rpc_2.dart';
import 'package:stream_channel/stream_channel.dart';

class IotController {
  Client? _client;
  
  Future<void> connect(String ip) async {
    var socket = await Socket.connect(ip, 8080);
    
    // 创建双向通道
    var channel = jsonDocument.bind(
      StreamChannel(socket, socket)
    );
    
    _client = Client(channel);
    _client!.listen(); // 启动循环
  }

  Future<void> toggleLed(bool on) async {
    if (_client == null || _client!.isClosed) throw Exception('Not connected');
    
    // 调用远程方法
    // 虽然是异步网络请求,写起来就像本地函数调用
    try {
      var response = await _client!.sendRequest('set_led', {'on': on});
      print('Response: $response');
    } catch (e) {
      print('RPC Error: $e');
    }
  }
}

这个例子展示了 json_rpc_2 最强大的能力:Transport Agnostic (传输无关性)。只要你能提供一个 StreamChannel,不管是 TCP、WebSocket,甚至是 Bluetooth RFCOMM,它都能跑起来。

在这里插入图片描述

四、高级进阶:批量请求 (Batch Request)

JSON-RPC 2.0 支持一次发送多个请求,常用于初始化大量数据。

// 客户端
client.withBatch(() {
  client.sendRequest('add', [1, 1]);
  client.sendRequest('add', [2, 2]);
  client.sendNotification('log', ['Batch test']);
}).then((results) {
  // results 包含所有返回结果
  print(results); // [2, 4, null] 
});

这对于移动网络环境极其友好,减少了 RTT(往返时延)。

五、总结

json_rpc_2 是 Dart 生态中被严重低估的一个库。它虽然看起来简单,但却是构建高可靠、低延迟、跨语言通信系统的基石。

与 gRPC 相比,它无需生成代码,调试只需 print;与 REST 相比,它支持全双工 Notification 推送。
对于 OpenHarmony 开发者,特别是涉及 硬件交互、即时通讯、区块链交互 的场景,JSON-RPC 是你的不二之选。

最佳实践

  1. 超时控制:在 sendRequest 后加上 .timeout(Duration(seconds: 5)),防止网络挂死。
  2. 错误定义:在服务端统一定义业务错误码(如 -32001 代表硬件故障),客户端据此做 UI 提示。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐