chrome设计时采用的一种方法是多进程技术(不仅限于此,也有其他方式),其中涉及到一个重要的问题就是进程间通信。
one tab, one process
可以从操作系统任务管理器以及CHROME自带的任务管理器可以看出,确实每个tab页,一个进程。
进程模型
浏览器进程负责进程管理以及进程通信。在浏览器进程中,有其他所有进程的标记,每个标记对应一个线程。浏览器对相关标记的操作,会被封装成消息,并发送给对应的Process来处理。
渲染进程嵌入WebKit来解析, 渲染和处理网页及网络应用。
进程间通信
在WINDOS平台,chrome采用命名管道进行进程间通信。
在ipc_channel.cc代码中有如下注释(Channels are implemented using named pipes on Windows)
服务器:
管道创建:CreateNamedPipe
等待链接:ConnectNamedPipe(类似于SOCKET中的LISTEN)
数据发送:WriteFile
数据接收:ReadFile
客户端
管道连接:CreateFile或者CallNamedPipe
数据发送:WriteFile
数据接收:ReadFile
CHROME进程间通信实现:
通信结构图
chrome中对进程间通信进行封装实现:CHANEL。
相关代码:ipc_channel.h ipc_sender.h ipc_reader.h ipc_listener.h ipc_channel_win.h及其CPP文件。
bool Channel::ChannelImpl::CreatePipe(const IPC::ChannelHandle &channel_handle,
Mode mode);
若FLAG为MODE_SERVER_FLAG,有如下代码:命名管道的创建
const DWORD open_mode = PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
FILE_FLAG_FIRST_PIPE_INSTANCE;
pipe_name = PipeName(channel_handle.name, &client_secret_);
pipe_ = CreateNamedPipeW(pipe_name.c_str(),
open_mode,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
1,
Channel::kReadBufferSize,
Channel::kReadBufferSize,
5000,
NULL);
若FLAG为MODE_CLIENT_FLAG,则为管道连接
pipe_name = PipeName(channel_handle.name, &client_secret_);
pipe_ = CreateFileW(pipe_name.c_str(),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION |
FILE_FLAG_OVERLAPPED,
NULL);
消息发送:
bool Channel::ChannelImpl::Send(Message* message) {
};
从管道中读取消息:根据管道句柄,设置数据缓冲区以及数据大小,直接读取即可。
Channel::ChannelImpl::ReadState Channel::ChannelImpl::ReadData(
char* buffer,
int buffer_len,
DWORD bytes_read = 0;
BOOL ok = ReadFile(pipe_, buffer, buffer_len,
&bytes_read, &input_state_.context.overlapped);
}
总结:
常用的IPC方式1. SOCKET:该方法不管是单机还是分布于不同计算机内的进程,都可以通信。SOCKET是全双工的。
2. 管道(Pipe):注:管道是单向的,如果要起到双向的结果,需要建立两条管道。
创建管道的程序成为管道服务器,连接到管道的程序成为管道客户机。
3. 共享内存:多个进程可以共同访问同一块内存。
4. 信号量、互斥量:该内核对象可以在进程间共享。起到进程间通信的效果
5. 消息队列:进程间可以通过消息队列进行通信。将消息发送到对方进程的消息队列中。
注:参考
1.《Google Chrome 浏览器架构解析及相关特性分析》
2. http://lihuan623.blog.163.com/blog/static/1385958452010449734597/