• VS Code For Web 深入浅出 -- 进程间通信篇


    在上一篇中,我们一起分析了 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
    }
    • 1
    • 2
    • 3
    • 4
    • 5

    从 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('testNotification');
    
    connection.listen();
    
    connection.sendNotification(notification, 'Hello World');
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    服务端调用也采用类似的包装:

    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('testNotification');
    connection.onNotification(notification, (param: string) => {
        console.log(param); // This prints Hello World
    });
    
    connection.listen();
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    进程间通信单元

    为了实现客户端与服务端之间的点对点通信,我们需要一个最小单元来实现消息的调用与监听。在 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(command: string, arg?: any, cancellationToken?: CancellationToken): Promise;
        listen(event: string, arg?: any): Event;
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    每次通信过程,需要客户端与服务端处于同一个 Channel 中。

    进程间通信建连

    在 VSCode 中,客户端与服务端之间的通信建立是通过 Connection 类来建立,通过传入客户端与服务端的 Channel ,即 ChannelClientChannelServer 来实例化连接。

    interface Connection extends Client {
        readonly channelServer: ChannelServer;
        readonly channelClient: ChannelClient;
    }
    • 1
    • 2
    • 3

    它们之间的区别是,由于服务端可以同时对多个客户端服务,因此支持多个 Channel 的获取,而ChannelClient 为一对一连接。

    综上,我们就梳理清楚了 VSCode 中 IPC 模块的基本架构,了解了进程间的通信细节。

    用一张图总结梳理一下知识点:

    20221010150243

    由于 VSCode 的 IPC 模块天然支持异步能力,因此事实上它并不区分进程是本地进程还是远端进程,只要是通过 Channel 通信的,都可以被认为是进程间通信,都可以复用相同的代码编写。

    参考

    VSCode 的官方文档

    VSCode API

    VSCode 源码解读--IPC 通信机制

    vscode 源码解析 - 进程间调用

  • 相关阅读:
    Spark-Scala语言实战(17)
    掌握C++魔法:深入解析类与对象(上篇)
    docker容器无法访问解决方法
    SpringBoot3 整合SpringSecurity
    UI组件库Kendo UI for Vue入门指南 - 如何自定义主题
    【毕业季|进击的技术er】作为一名职场人,精心总结的嵌入式学习路线图
    会议管理系统SSM记录(一)
    定制化JDK升级引发的离奇事件
    软件测试面试题
    百题千解计划【CSDN每日一练】收件邮箱(使用Python、Java、JavaScript解决)无敌的Python正则表达式、零宽负向断言
  • 原文地址:https://blog.csdn.net/kelekexiao123/article/details/127423866