在上一篇中,我们一起分析了 VS Code 整体的代码架构,了解了 VS Code 是由前后端分离的方式开发的 。且无论前端是基于 electron 还是 web,后端是本地还是云端,其调用方式并无不同 。
这样的架构下,前后端的通信方式是如何实现的呢?本篇我们将一起来探究 VS Code For Web 的进程间通信方式 。
进程通信与调用方式进程间通信协议对于多进程架构的项目,进程之间的通信会通过进程间调用 (Inter Process Calling, IPC) 。VSCode 中自己设计了专门的 IPC 模块来实现通信 。代码位于 src/vs/base/parts/ipc 。
export const enum RequestType {Promise = 100,PromiseCancel = 101,EventListen = 102,EventDispose = 103}
从 enum type 可以看出,VSCode 的 IPC 模块同时支持两种调用方式,一种是基于 Promise 的调用实现,另一种是通过 Event Emitter/Listener 的那一套事件监听机制来实现 。
以事件监听机制为例,VSCode 中采用 vscode-jsonrpc
这个包来封装实现,调用方式如下:
import * as cp from 'child_process';import * as rpc from 'vscode-jsonrpc/node';let childProcess = cp.spawn(...);// Use stdin and stdout for communication:let connection = rpc.createMessageConnection(new rpc.StreamMessageReader(childProcess.stdout),new rpc.StreamMessageWriter(childProcess.stdin));let notification = new rpc.NotificationType<string, void>('testNotification');connection.listen();connection.sendNotification(notification, 'Hello World');
服务端调用也采用类似的包装:
import * as rpc from 'vscode-jsonrpc/node';let connection = rpc.createMessageConnection(new rpc.StreamMessageReader(process.stdin),new rpc.StreamMessageWriter(process.stdout));let notification = new rpc.NotificationType<string, void>('testNotification');connection.onNotification(notification, (param: string) => {console.log(param); // This prints Hello World});connection.listen();
进程间通信单元为了实现客户端与服务端之间的点对点通信,我们需要一个最小单元来实现消息的调用与监听 。在 VSCode 中,这个最小单元即为 Channel
。
/** * An `IChannel` is an abstraction over a collection of commands. * You can `call` several commands on a channel, each taking at * most one single argument. A `call` always returns a promise * with at most one single return value. */export interface IChannel {call<T>(command: string, arg?: any, cancellationToken?: CancellationToken): Promise<T>;listen<T>(event: string, arg?: any): Event<T>;}
每次通信过程,需要客户端与服务端处于同一个 Channel
中 。
进程间通信建连在 VSCode 中,客户端与服务端之间的通信建立是通过 Connection
类来建立,通过传入客户端与服务端的 Channel
,即 ChannelClient
与 ChannelServer
来实例化连接 。
interface Connection<TContext> extends Client<TContext> {readonly channelServer: ChannelServer<TContext>;readonly channelClient: ChannelClient;}
它们之间的区别是,由于服务端可以同时对多个客户端服务,因此支持多个 Channel
的获取,而ChannelClient
为一对一连接 。
综上,我们就梳理清楚了 VSCode 中 IPC 模块的基本架构,了解了进程间的通信细节 。
用一张图总结梳理一下知识点:
文章插图
由于 VSCode 的 IPC 模块天然支持异步能力,因此事实上它并不区分进程是本地进程还是远端进程,只要是通过
Channel
通信的,都可以被认为是进程间通信,都可以复用相同的代码编写 。参考VSCode 的官方文档
VSCode API
VSCode 源码解读--IPC 通信机制
经验总结扩展阅读
- 【算法训练营day8】LeetCode344. 反转字符串 LeetCode541. 反转字符串II 剑指Offer05. 替换空格 LeetCode151. 翻转字符串里的单词 剑指Offer58-II. 左旋转字符串
- 【算法训练营day7】LeetCode454. 四数相加II LeetCode383. 赎金信 LeetCode15. 三数之和 LeetCode18. 四数之和
- [题解] Atcoder Regular Contest ARC 151 A B C D E 题解
- VS Code For Web 深入浅出 -- 导读篇
- 【算法训练营day4】LeetCode24. 两两交换链表中的结点
- asp.net core web 解决方案多项目模板制作打包总结
- JavaWeb完整案例详细步骤
- React魔法堂:echarts-for-react源码略读
- Maximum Entropy Population-Based Training for Zero-Shot Human-AI Coordination
- 重写 hashcode真有那么简单嘛?