一、框架概览
MetaMask JSON-RPC 框架是处理请求的基础组件。它主要由以下几个核心仓库(repo)组成:
- json-rpc-engine:核心引擎,负责 JSON-RPC 请求的中间件链式处理。
- eth-json-rpc-filters:实现以太坊的 filter 相关方法(如日志、区块订阅)。
- eth-json-rpc-middleware:提供丰富的以太坊 JSON-RPC 中间件(如账户、签名、网络等)。
- eth-json-rpc-provider:实现 provider 接口,适配不同的 JSON-RPC 后端。
- json-rpc-middleware-stream:用于流式(stream)环境下的 JSON-RPC 通信。
其中,json-rpc-engine 是整个体系的核心,其他库大多围绕它进行扩展和集成。
总体架构图:
二、json-rpc-engine 详解
源码地址:github.com/MetaMask/co...
1. 设计理念
json-rpc-engine
借鉴了 Koa/Express 等 Web 框架的中间件(middleware)机制,将 JSON-RPC 请求的处理流程拆解为一系列可插拔的中间件,每个中间件只关注自己的职责,极大提升了可维护性和可扩展性。
2. 基本用法
创建引擎
javascript
const { JsonRpcEngine } = require('@metamask/json-rpc-engine');
const engine = new JsonRpcEngine();
添加中间件
javascript
engine.push((req, res, next, end) => {
// 处理请求
if (req.method === 'hello') {
res.result = 'world';
return end();
}
next();
});
发送请求
javascript
engine.handle({ id: 1, jsonrpc: '2.0', method: 'hello' }, (err, res) => {
console.log(res.result); // 输出 'world'
});
3. 中间件机制
每个中间件函数签名如下:
javascript
function middleware(req, res, next, end) {
// req: 请求对象
// res: 响应对象
// next: 进入下一个中间件
// end: 终止链式调用(可传递错误)
}
next()
:继续传递到下一个中间件。end()
:终止处理流程,返回响应。- 异步支持 :支持
async/await
,允许中间件异步处理。
示例:日志中间件
javascript
engine.push((req, res, next, end) => {
console.log('请求方法:', req.method);
next();
});
4. 典型应用场景
- 权限控制:如只允许白名单方法通过。
- 缓存:如对某些请求结果做缓存。
- 签名/账户管理 :如拦截
eth_sign
、eth_accounts
等方法。 - 网络代理:如将请求转发到远程节点。
5. 核心源码解读
核心方法是 #runMiddleware
,用于执行中间件方法。
方法签名
typescript
static async #runMiddleware(
request: JsonRpcRequest,
response: PendingJsonRpcResponse<Json>,
middleware: JsonRpcMiddleware<JsonRpcParams, Json>,
returnHandlers: JsonRpcEngineReturnHandler[],
): Promise<[unknown, boolean]>
request
:当前的 JSON-RPC 请求对象。response
:当前的响应对象。middleware
:要执行的中间件函数。returnHandlers
:用于收集 return handler 的数组。- 返回值 :Promise,resolve 时返回
[error, isComplete]
,即本中间件是否终结了请求。
主要流程
Promise 封装
整个方法用 Promise 封装,便于异步链式调用和错误捕获。
end
回调
typescript
const end: JsonRpcEngineEndCallback = (error) => {
const parsedError = error || response.error;
if (parsedError) {
response.error = serializeError(parsedError);
}
// True indicates that the request should end
resolve([parsedError, true]);
};
- 作用 :中间件调用
end()
时触发,表示本次请求处理终止。 - 行为 :
- 如果有错误,序列化并写入
response.error
。 - resolve Promise,返回
[error, true]
,true
表示请求已终结。
- 如果有错误,序列化并写入
next
回调
typescript
const next: JsonRpcEngineNextCallback = (
returnHandler?: JsonRpcEngineReturnHandler,
) => {
if (response.error) {
end(response.error);
} else {
if (returnHandler) {
if (typeof returnHandler !== 'function') {
end(
new JsonRpcError(
errorCodes.rpc.internal,
`JsonRpcEngine: "next" return handlers must be functions. ` +
`Received "${typeof returnHandler}" for request:\n${jsonify(
request,
)}`,
{ request },
),
);
}
returnHandlers.push(returnHandler);
}
// False indicates that the request should not end
resolve([null, false]);
}
};
- 作用 :中间件调用
next()
时触发,表示继续传递到下一个中间件。 - 行为 :
- 如果
response
已有 error,直接调用end
。 - 如果传入了
returnHandler
,类型检查后加入returnHandlers
数组。 - resolve Promise,返回
[null, false]
,false
表示请求未终结,还需继续后续中间件。
- 如果
执行中间件
typescript
try {
middleware(request, response, next, end);
} catch (error) {
end(error);
}
- 作用:实际调用传入的中间件函数。
- 行为 :
- 传入
request
、response
、next
、end
四个参数。 - 如果中间件抛出异常,捕获并调用
end
。
- 传入
例子
javascript
engine.push((req, res, next, end) => {
// 前置逻辑
next(async () => {
// 后置逻辑
});
});
- 当中间件调用
next(returnHandler)
时,returnHandler
被收集到returnHandlers
。 - 当所有中间件正向执行完毕后,engine 会逆序执行
returnHandlers
。
6. 其他工具方法
createAsyncMiddleware
用于将基于 async/await
的异步中间件包装成 engine 能识别的"回调风格"中间件。
javascript
engine.push(createAsyncMiddleware(async (req, res, next) => {
// 前置逻辑
await next();
// 后置逻辑
}));
等价于 callback 风格:
javascript
engine.push((req, res, next, end) => {
// 前置逻辑
next(() => {
// 后置逻辑
});
});
mergeMiddleware
将多个中间件合并成一个中间件,便于批量插入或动态组合。
javascript
const { mergeMiddleware } = require('@metamask/json-rpc-engine');
const middlewareA = (req, res, next, end) => {
if (req.method === 'foo') {
res.result = 'bar';
return end();
}
next();
};
const middlewareB = (req, res, next, end) => {
if (req.method === 'hello') {
res.result = 'world';
return end();
}
next();
};
// 合并为一个中间件
const combined = mergeMiddleware([middlewareA, middlewareB]);
engine.push(combined);
foo
方法会被 middlewareA
处理,hello
方法会被 middlewareB
处理,其他请求继续传递。
asMiddleware
将一个 JsonRpcEngine
实例包装成一个中间件,可以嵌套引擎,实现模块化拆分。
javascript
const { JsonRpcEngine } = require('@metamask/json-rpc-engine');
// 子引擎
const subEngine = new JsonRpcEngine();
subEngine.push((req, res, next, end) => {
if (req.method === 'sub_method') {
res.result = 'from subEngine';
return end();
}
next();
});
// 主引擎
const mainEngine = new JsonRpcEngine();
mainEngine.push(subEngine.asMiddleware()); // 嵌套子引擎
mainEngine.push((req, res, next, end) => {
res.result = 'from mainEngine';
end();
});
// 测试
mainEngine.handle({ id: 1, jsonrpc: '2.0', method: 'sub_method' }, (err, res) => {
console.log(res.result); // 输出 'from subEngine'
});
sub_method
由 subEngine
处理,其他方法由 mainEngine
处理。
createScaffoldMiddleware
用于根据传入的 method-handler
映射对象,快速生成一个支持静态返回或自定义处理函数的 JSON-RPC 中间件。
源码实现
javascript
export function createScaffoldMiddleware(handlers: {
[methodName: string]: ScaffoldMiddlewareHandler<JsonRpcParams, Json>;
}): JsonRpcMiddleware<JsonRpcParams, Json> {
return (req, res, next, end) => {
const handler = handlers[req.method];
// if no handler, return
if (handler === undefined) {
return next();
}
// if handler is fn, call as middleware
if (typeof handler === 'function') {
return handler(req, res, next, end);
}
// if handler is some other value, use as result
(res as JsonRpcSuccess<Json>).result = handler;
return end();
};
}
用法
javascript
const { createScaffoldMiddleware } = require('@metamask/json-rpc-engine');
const scaffold = createScaffoldMiddleware({
eth_chainId: '0x1',
net_version: '1',
web3_clientVersion: async () => 'MyClient/v1.0.0',
});
engine.push(scaffold);
// 测试
engine.handle({ id: 1, jsonrpc: '2.0', method: 'eth_chainId' }, (err, res) => {
console.log(res.result); // 输出 '0x1'
});
engine.handle({ id: 2, jsonrpc: '2.0', method: 'web3_clientVersion' }, (err, res) => {
console.log(res.result); // 输出 'MyClient/v1.0.0'
});
三、其他 RPC 组件
1. eth-json-rpc-provider
eth-json-rpc-provider
提供了将 engine
或 middleware
封装为标准以太坊 Provider 的能力。JsonRpcEngine
里最后一个 middleware
通常就是把 eth-json-rpc-provider
(链上请求执行者)包装成中间件,最终通过 request
方法把请求发到链上。
request
实现
javascript
async request<Params extends JsonRpcParams, Result extends Json>(
eip1193Request: Eip1193Request<Params>,
): Promise<Result> {
const jsonRpcRequest =
convertEip1193RequestToJsonRpcRequest(eip1193Request);
const response = await this.#engine.handle<
Params | Record<never, never>,
Result
>(jsonRpcRequest);
if ('result' in response) {
return response.result;
}
const error = new JsonRpcError(
response.error.code,
response.error.message,
response.error.data,
);
if ('stack' in response.error) {
error.stack = response.error.stack;
}
throw error;
}
2. json-rpc-middleware-stream
主要有两个核心方法:
createEngineStream
将 JsonRpcEngine
包装成 stream
形式,兼容流式通信架构。
javascript
export default function createEngineStream(opts: JsonRpcEngine): Duplex {
if (!opts?.engine) {
throw new Error('Missing engine parameter!');
}
const { engine } = opts;
const stream = new Duplex({ objectMode: true, read: () => undefined, write });
// 转发 engine 的 notification 事件
if (engine.on) {
engine.on('notification', (message) => {
stream.push(message);
});
}
return stream;
function write(
req: JsonRpcRequest,
_encoding: unknown,
streamWriteCallback: (error?: Error | null) => void,
) {
// 处理请求并将请求传递给下游 stream
engine.handle(req, (_err, res) => {
stream.push(res);
});
streamWriteCallback();
}
}
createStreamMiddleware
createStreamMiddleware
的作用是在 JSON-RPC Engine 和底层流式通信通道(如 MessagePort、WebSocket、内容脚本与后台脚本之间的 stream)之间,充当桥接中间件,实现请求和通知的双向流转。
详细说明
- 当网页中注入的 provider(如
window.ethereum
)发起 JSON-RPC 请求时,这些请求会通过 engine 传递到createStreamMiddleware
生成的 middleware。 createStreamMiddleware
会将收到的请求对象写入下游的 stream(如内容脚本与后台的连接流),实现请求的跨上下文转发。- 当下游 stream(如后台脚本)处理完请求并返回响应时,
createStreamMiddleware
会自动将响应回填到原始请求的响应对象,并调用end()
,完成一次完整的请求-响应闭环。 - 此外,当下游 stream 推送通知(如账户变更、链变更、订阅事件等)时,
createStreamMiddleware
会自动触发自身的notification
事件。开发者可以监听该事件,及时处理链上状态变更或推送消息。 - 该中间件还支持重试机制(如
retryOnMessage
),在特定消息下自动重发未完成的请求,提升健壮性。
典型流程
provider.request
→engine
→createStreamMiddleware.middleware
→ 下游 stream → 下游 stream 响应 →createStreamMiddleware
识别响应 → 回填到原始请求。- 下游 stream 推送通知 →
createStreamMiddleware
触发notification
事件 → provider 监听并处理。
代码场景举例
javascript
// 1. 创建中间件和 stream
const { middleware, stream, events } = createStreamMiddleware({ retryOnMessage: 'SOME_RETRY_SIGNAL' });
// 2. 连接上下游 stream
pipeline(connectionStream, stream, connectionStream, ...);
// 3. 将中间件添加到 engine
engine.push(middleware);
// 4. 监听 notification 事件
events.on('notification', (payload) => {
// 处理链变更、账户变更等通知
});
源码
javascript
export default function createStreamMiddleware(options: Options = {}) {
const idMap: IdMap = {}; // 请求 id 到上下文的映射
const stream = new Duplex({
objectMode: true,
read: () => undefined,
write: processMessage,
});
const events = new SafeEventEmitter();
// 核心中间件:将请求写入流,等待响应
const middleware: JsonRpcMiddleware<JsonRpcParams, JsonRpcParams> = (
req,
res,
next,
end,
) => {
// 先注册请求上下文,防止响应先到
idMap[req.id as unknown as string] = { req, res, next, end };
sendToStream(req);
};
return { events, middleware, stream };
// 发送请求到下游流
function sendToStream(req: JsonRpcRequest) {
stream.push(req);
}
// 处理流上收到的消息(响应或通知)
function processMessage(
res: PendingJsonRpcResponse<JsonRpcParams>,
_encoding: unknown,
streamWriteCallback: (error?: Error | null) => void,
) {
let errorObj: Error | null = null;
try {
const isNotification = !hasProperty(res, 'id');
if (isNotification) {
processNotification(res as unknown as JsonRpcNotification);
} else {
processResponse(res);
}
} catch (_err) {
errorObj = _err as Error;
}
streamWriteCallback(errorObj);
}
// 处理 JSON-RPC 响应,回填到原始请求上下文
function processResponse(res: PendingJsonRpcResponse<JsonRpcParams>) {
const { id: responseId } = res;
if (responseId === null) {
return;
}
const context = idMap[responseId];
if (!context) {
console.warn(`StreamMiddleware - Unknown response id "${responseId}"`);
return;
}
delete idMap[responseId];
Object.assign(context.res, res); // 响应内容写回原始 res
setTimeout(context.end); // 异步调用 end,完成请求
}
// 处理 JSON-RPC 通知,转发为事件
function processNotification(notif: JsonRpcNotification) {
if (options?.retryOnMessage && notif.method === options.retryOnMessage) {
retryStuckRequests();
}
events.emit('notification', notif); // 通知事件转发
}
// 重试所有未完成的请求
function retryStuckRequests() {
Object.values(idMap).forEach(({ req, retryCount = 0 }) => {
if (!req.id) {
return;
}
if (retryCount >= 3) {
throw new Error(
`StreamMiddleware - Retry limit exceeded for request id "${req.id}"`,
);
}
const idMapObject = idMap[req.id];
if (idMapObject) {
idMapObject.retryCount = retryCount + 1;
}
sendToStream(req); // 重新发送请求
});
}
}
3. eth-json-rpc-middleware
JSON-RPC 框架中的中间件集合,为 JsonRpcEngine
提供丰富的功能扩展。这些中间件可以像乐高积木一样自由组合,拦截、处理、缓存、转发、增强 JSON-RPC 请求。
主要文件与功能
-
wallet.ts
:- 功能:实现与钱包相关的核心中间件,如账户管理、签名、交易发送等。
- 用途 :拦截如
eth_accounts
、eth_sendTransaction
、eth_sign
等请求,调用本地钱包逻辑处理。
-
fetch.ts
:- 功能:实现将 JSON-RPC 请求通过 HTTP(s) 发送到远程节点(如 Infura、自建节点)。
- 用途:通常作为 engine 的最后一个中间件,兜底处理所有未被前面中间件处理的请求。
-
providerAsMiddleware.ts
:- 功能:将标准 provider(如 ethers.js/web3.js provider)适配为 engine 可用的 middleware。
- 用途:便于集成第三方 provider 作为 engine 的一环。
-
retryOnEmpty.ts
:- 功能:对返回空结果的请求自动重试,提升健壮性。
- 用途:常用于区块、交易等可能因节点同步延迟而暂时查不到结果的场景。
-
inflight-cache.ts
:- 功能:对相同参数的并发请求做缓存,避免重复请求,提升性能。
- 用途:如多个 DApp 同时请求同一个区块或账户信息时,只发一次请求。
-
block-cache.ts / block-ref.ts / block-ref-rewrite.ts / block-tracker-inspector.ts
:- 功能:与区块相关的缓存、引用重写、区块追踪等功能。
- 用途:提升区块数据的获取效率,支持区块快照、缓存、重写等高级用法。
典型用法
javascript
import { JsonRpcEngine } from '@metamask/json-rpc-engine';
import { createWalletMiddleware, createFetchMiddleware, createInflightCacheMiddleware } from './eth-json-rpc-middleware';
const engine = new JsonRpcEngine();
engine.push(createInflightCacheMiddleware());
engine.push(createWalletMiddleware({ getAccounts, signTransaction, ... }));
engine.push(createFetchMiddleware({ rpcUrl: 'https://mainnet.infura.io/v3/xxx' }));
这样,engine 会先查缓存,再走本地钱包逻辑,最后兜底发到远程节点。
由于中间件过多,不可能全部讲解,这里我们着重介绍 wallet
和 fetch
中间件:
wallet
wallet.ts
实现了与本地钱包相关的核心 JSON-RPC 方法拦截和处理。
拦截的 JSON-RPC 方法:
注意 :下列方法大部分不是以太坊的标准 RPC 命令,而是 MetaMask 定制化的命令如 wallet_xxx
,有些和以太坊标准命令同名但实现也不仅仅是直接把命令转发到链上,中间有复杂的处理可参考源码或文档:docs.metamask.io/wallet/how-...
eth_accounts
:返回当前钱包管理的所有账户地址数组。eth_coinbase
:返回当前钱包的主账户地址(通常是第一个账户)。eth_sendTransaction
:发起链上交易,由钱包弹窗确认并签名后广播。eth_signTransaction
:对交易数据进行签名但不广播,仅返回签名结果。eth_signTypedData / eth_signTypedData_v3 / eth_signTypedData_v4
:对结构化数据(EIP-712)进行签名,常用于合约交互和链下授权。personal_sign
:对任意消息进行签名,常用于链下认证和登录。eth_getEncryptionPublicKey
:获取账户的加密公钥,用于加密消息。eth_decrypt
:用账户私钥解密加密消息。personal_ecRecover
:从签名和消息中恢复出签名者的地址。wallet_getCapabilities
:查询钱包支持的扩展能力列表。wallet_sendCalls
:批量发送多条链上调用,实现高效批量操作。wallet_getCallsStatus
:查询批量调用的执行状态和结果。
javascript
// `getAccounts`、`getCallsStatus` 等函数作为依赖通过参数传递进 `createWalletMiddleware`,中间件内
// 部会先进行一些前置处理(如参数校验、权限检查、格式转换等),然后再调用这些实际的业务实现函数。真正的
//业务逻辑函数(如 `getAccounts`、`getCallsStatus` 的具体实现)位于 `metamask-controller.js` 中,由
//控制器负责与底层钱包数据和链上交互,确保中间件与核心逻辑解耦
export function createWalletMiddleware({
getAccounts,
getCallsStatus,
getCapabilities,
processDecryptMessage,
processEncryptionPublicKey,
processPersonalMessage,
processTransaction,
processSignTransaction,
processTypedMessage,
processTypedMessageV3,
processTypedMessageV4,
processSendCalls,
}:
WalletMiddlewareOptions): JsonRpcMiddleware<any, Block> {
if (!getAccounts) {
throw new Error('opts.getAccounts is required');
}
return createScaffoldMiddleware({
// account lookups
eth_accounts: createAsyncMiddleware(lookupAccounts),
eth_coinbase: createAsyncMiddleware(lookupDefaultAccount),
// tx signatures
eth_sendTransaction: createAsyncMiddleware(sendTransaction),
eth_signTransaction: createAsyncMiddleware(signTransaction),
// message signatures
eth_signTypedData: createAsyncMiddleware(signTypedData),
eth_signTypedData_v3: createAsyncMiddleware(signTypedDataV3),
eth_signTypedData_v4: createAsyncMiddleware(signTypedDataV4),
personal_sign: createAsyncMiddleware(personalSign),
eth_getEncryptionPublicKey: createAsyncMiddleware(encryptionPublicKey),
eth_decrypt: createAsyncMiddleware(decryptMessage),
personal_ecRecover: createAsyncMiddleware(personalRecover),
// EIP-5792
wallet_getCapabilities: createAsyncMiddleware(async (params, req) =>
walletGetCapabilities(params, req, { getAccounts, getCapabilities }),
),
wallet_sendCalls: createAsyncMiddleware(async (params, req) =>
walletSendCalls(params, req, { getAccounts, processSendCalls }),
),
wallet_getCallsStatus: createAsyncMiddleware(async (params, req) =>
walletGetCallsStatus(params, req, {
getCallsStatus,
}),
),
});
fetch
fetch.ts
实现了将 JSON-RPC 请求通过 HTTP(s) 发送到远程以太坊节点(如 Infura、自建节点),是 engine 的"兜底"中间件。所谓"兜底"中间件,就是只有当前面的中间件都没有终结请求时 fetchMiddleware
才会作为兜底中间件处理该请求,把它发到远程节点。我们前面说 eth-json-rpc-provider
通常作为最后一个中间件,和这里的描述冲突,实际上 eth-json-rpc-provider
更为通用,内部仍然是封装的 fetchMiddleware
。
核心代码:
javascript
function createFetchMiddlewareWithRpcService({
rpcService,
options = {},
}: {
rpcService: AbstractRpcService;
options?: {
originHttpHeaderKey?: string;
};
}): JsonRpcMiddleware<JsonRpcParams, Json> {
return createAsyncMiddleware(
async (req: JsonRpcRequestWithOrigin<JsonRpcParams>, res) => {
const headers =
'originHttpHeaderKey' in options &&
options.originHttpHeaderKey !== undefined &&
req.origin !== undefined
? { [options.originHttpHeaderKey]: req.origin }
: {};
// 发送请求到远程节点,进行链上处理
const jsonRpcResponse = await rpcService.request(
{
id: req.id,
jsonrpc: req.jsonrpc,
method: req.method,
params: req.params,
},
{
headers,
},
);
if ('error' in jsonRpcResponse) {
throw rpcErrors.internal({
data: jsonRpcResponse.error,
});
}
res.result = jsonRpcResponse.result;
},
);
}
4. eth-json-rpc-filters
createEthFilterMiddleware
实现了以太坊 JSON-RPC filter 相关方法的中间件,统一管理日志、区块、pending 交易等过滤器的创建、更新、查询和销毁,为 DApp 提供链上事件订阅与筛选能力。
使用方法 :DApp 需定期轮询调用 getFilterChanges
获取新事件。
javascript
window.ethereum.request({ method: 'eth_newFilter', ... }) + 轮询
javascript
// index.js
function createEthFilterMiddleware({ blockTracker, provider }) {
return createScaffoldMiddleware({
// install filters
eth_newFilter: waitForFree(toFilterCreationMiddleware(newLogFilter)),
eth_newBlockFilter: waitForFree(toFilterCreationMiddleware(newBlockFilter)),
eth_newPendingTransactionFilter: waitForFree(toFilterCreationMiddleware(newPendingTransactionFilter)),
// uninstall filters
eth_uninstallFilter: waitForFree(toAsyncRpcMiddleware(uninstallFilterHandler)),
// checking filter changes
eth_getFilterChanges: waitForFree(toAsyncRpcMiddleware(getFilterChanges)),
eth_getFilterLogs: waitForFree(toAsyncRpcMiddleware(getFilterLogs)),
});
}
createSubscriptionMiddleware
通过用事件封装 EthFilterMiddleware
实现发布订阅机制。
使用方法:DApp 订阅后自动收到事件通知。
javascript
window.ethereum.request({ method: 'eth_subscribe', ... }) + 监听事件
javascript
// subscriptionManager.js
function createSubscriptionMiddleware({ blockTracker, provider }) {
// state and utilities for handling subscriptions
const subscriptions = {};
const filterManager = createFilterMiddleware({ blockTracker, provider });
// internal flag
let isDestroyed = false;
// create subscriptionManager api object
const events = new SafeEventEmitter();
const middleware = createScaffoldMiddleware({
eth_subscribe: createAsyncMiddleware(subscribe),
eth_unsubscribe: createAsyncMiddleware(unsubscribe),
});
middleware.destroy = destroy;
return { events, middleware };
}
5. RpcService
这部分严格来说不属于JSON PRC框架本身,它是用来管理JSON-RPC服务,提供故障恢复与转移、重试、熔断、降级等机制,确保网络请求的高可用性。 详细介绍参考:区块链钱包开发------构建网络控制器(network-controller)
四、总结
在 MetaMask 的实现中,JSON RPC 框架通过中间件机制来处理请求和响应,支持多种以太坊(后面也将支持 Solana 和 BTC)相关的操作,如账户管理、交易发送和事件订阅等。中间件可以在请求处理的不同阶段插入自定义逻辑,从而实现功能扩展和错误处理。通过这种方式,开发者可以灵活地构建和管理与以太坊区块链的交互。
学习交流请添加vx: gh313061
本教程配套视频教程:space.bilibili.com/382494787/l...
下期预告:构建各个控制器间的通信框架