38|浏览器原理(二):浏览器进程通信与网络渲染详解 您所在的位置:网站首页 进程间通信的途径有哪些 38|浏览器原理(二):浏览器进程通信与网络渲染详解

38|浏览器原理(二):浏览器进程通信与网络渲染详解

2024-07-08 20:12| 来源: 网络整理| 查看: 265

38|浏览器原理(二):浏览器进程通信与网络渲染详解

你好,我是LMOS。

通过前面的学习,你应该对浏览器内的进程和线程已经有了一个大概的印象,也知道了为了避免一些问题,现代浏览器采用了多进程架构。

这节课,我们首先要说的是Chrome中的进程通信。这么多的进程,它们之间是如何进行IPC通信的呢?要知道,如果IPC通信设计得不合理,就会引发非常多的问题。

Chrome如何进行进程间的通信

上节课 我们提了一下Chrome进程架构,Chrome有很多类型的进程。这些进程之间需要进行数据交换,其中有一个浏览器主进程,每个页面会使用一个渲染进程,每个插件会使用一个插件进程。除此之外,还有网络进程和GPU进程等功能性进程。

进程之间需要进程通信,渲染进程和插件进程需要同网络和GPU等进程通信,借助操作系统的功能来完成部分功能。其次,同一类进程(如多个渲染进程)之间不可以直接通信,需要依赖主进程进行调度中转。

进程与进程之间的通信,也离不开操作系统的支持。在前面讲IPC的时候,我们了解过多种实现方式。这里我们来看看Chrome的源码,Chrome中IPC的具体实现是通过IPC::Channel这个类实现的,具体在 ipc/ipc_channel.cc 这个文件中封装了实现的细节。

但是在查阅代码的过程中,我发现 Chrome 已经不推荐使用IPC::Channel机制进行通信了,Chrome 实现了一种新的 IPC 机制—— Mojo。

目前IPC::Channel 底层也是基于 Mojo 来实现的,但是上层接口和旧的 Chrome IPC 保持兼容,IPC::Channel 这种方式即将被淘汰,所以这里我们先重点关注 Mojo,后面我们再简单了解一下 Chrome IPC 接口。

Mojo

Mojo 是一个跨平台 IPC 框架,它源于 Chromium 项目,主要用于进程间的通信,ChromeOS 用的也是Mojo框架。

Mojo官方文档给出的定义是这样的:

“Mojo是运行时库的集合,这些运行时库提供了与平台无关的通用IPC原语抽象、消息IDL格式以及具有用于多重目标语言的代码生成功能的绑定库,以方便在任意跨进程、进程内边界传递消息。”

在这里插入图片描述

在Chromium中,有两个基础模块使用 Mojo,分别是 Services 和 IPC::Channel。

Services 是一种更高层次的 IPC 机制,底层通过 Mojo 来实现。Chromium 大量使用这种IPC机制来包装各种功能服务,用来取代 IPC::Channel ,比如 device 服务,performance 服务,audio 服务,viz 服务等。

Mojo 支持在 多个 进程之间互相通信,这一点和其他的IPC有很大的不同,其他IPC大多只支持2个进程之间进行通信。

这些由Mojo组成的、可以互相通信的进程就形成了一个网络。在这个网络内,任意两个进程都可以进行通信,并且每个进程只能处于一个 Mojo 网络中,每一个进程内部有且只有一个 Node,每一个 Node 可以提供多个 Port,每个 Port 对应一种服务,这点类似 TCP/IP 中的 IP 地址和端口的关系。一个 Node:port 对可以唯一确定一个服务。

Node 和 Node 之间通过 Channel 来实现通信,在不同平台上 Channel 有不同的实现方式:在Linux上是Domain Socket;在Windows上是Named Pipe;在macOS平台上是 Mach Port。

在 Port 的上一层,Mojo 封装了3个“应用层协议”,分别为MessagePipe,DataPipe和SharedBuffer(这里你是不是感觉很像网络栈,在 TCP 上封装了 HTTP)。整体结构如下图:

在这里插入图片描述

我们在 Chromium 代码中使用 Mojo,是不必做 Mojo 初始化相关工作的,因为这部分Chromium 代码已经做好了。如果我们在 Chromium 之外的工程使用 Mojo,还需要做一些初始化的工作,代码如下:

int main(int argc, char** argv) { // 初始化CommandLine,DataPipe 依赖它 base::CommandLine::Init(argc, argv); // 初始化 mojo mojo::core::Init(); // 创建一个线程,用于Mojo内部收发数据 base::Thread ipc_thread("ipc!"); ipc_thread.StartWithOptions( base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); // 初始化 Mojo 的IPC支持,只有初始化后进程间的Mojo通信才能有效 // 这个对象要保证一直存活,否则IPC通信就会断开 mojo::core::ScopedIPCSupport ipc_support( ipc_thread.task_runner(), mojo::core::ScopedIPCSupport::ShutdownPolicy::CLEAN); // ... }

MessagePipe 用于进程间的双向通信,类似UDP,消息是基于数据报文的,底层使用 Channel通道;SharedBuffer 支持双向块数据传递,底层使用系统 Shared Memory 实现;DataPipe 用于进程间单向块数据传递,类似TCP,消息是基于数据流的,底层使用系统的 Shared Memory实现。

一个 MessagePipe 中有一对 handle,分别是 handle0 和 handle1,MessagePipe 向其中一个handle写的数据可以从另外一个handle读出来。如果把其中的一个 handle 发送到另外一个进程,这一对 handle 之间依然能够相互收发数据。

Mojo 提供了多种方法来发送 handle 到其他的进程,其中最简单的是使用 Invitation。要在多个进程间使用 Mojo,必须先通过 Invitation 将这些进程“连接”起来,这需要一个进程发送Invitation,另一个进程接收 Invitation。

发送Invitation的方法如下:

// 创建一条系统级的IPC通信通道 // 在Linux上是 Domain Socket, Windows 是 Named Pipe,macOS是Mach Port,该通道用于支持跨进程的消息通信 mojo::PlatformChannel channel; LOG(INFO)


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有