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/