上来就被这个复杂的define给搞迷糊了,看了http://www.cnblogs.com/duguguiyu/archive/2008/10/04/1303695.html
的解释,在对照就好多了,不过他的介绍里有些错误,而且一些关键点没有写
最牛逼的就是自动生成id和挂钩Id了,用mfc的人都知道,自定义消息的时候都要去写um_xx这种定义,然后要写messagemap,再写实现,chrome把这步简化多了
介绍下,首先它定义了他需要用到的一些消息种类,
这个就是 label##MsgStart了
#define IPC_BEGIN_MESSAGES(label) /
enum label##MsgType { /
label##Start = label##MsgStart << 16, /
label##PreStart = (label##MsgStart << 16) - 1,
enum IPCMessageStart { // By using a start value of 0 for automation messages, we keep backward // compatibility with old builds. AutomationMsgStart = 0, ViewMsgStart, ViewHostMsgStart, PluginProcessMsgStart, PluginProcessHostMsgStart, PluginMsgStart, PluginHostMsgStart, ProfileImportProcessMsgStart, ProfileImportProcessHostMsgStart, NPObjectMsgStart, TestMsgStart, DevToolsAgentMsgStart, DevToolsClientMsgStart, WorkerProcessMsgStart, WorkerProcessHostMsgStart, WorkerMsgStart, WorkerHostMsgStart, NaClProcessMsgStart, GpuCommandBufferMsgStart, UtilityMsgStart, UtilityHostMsgStart, GpuMsgStart, GpuHostMsgStart, GpuChannelMsgStart, // NOTE: When you add a new message class, also update // IPCStatusView::IPCStatusView to ensure logging works. LastMsgIndex };
.h互相嵌套,这可是平时编程时的禁区
#ifndef IPC_MESSAGE_MACROS_INCLUDE_BLOCK #define IPC_MESSAGE_MACROS_INCLUDE_BLOCK // Multi-pass include of X_messages_internal.h. Preprocessor magic allows // us to use 1 header to define the enums and classes for our render messages. #define IPC_MESSAGE_MACROS_ENUMS #include MESSAGES_INTERNAL_FILE #define IPC_MESSAGE_MACROS_CLASSES #include MESSAGES_INTERNAL_FILE #ifdef IPC_MESSAGE_MACROS_LOG_ENABLED #define IPC_MESSAGE_MACROS_LOG #include MESSAGES_INTERNAL_FILE #endif #undef MESSAGES_INTERNAL_FILE #undef IPC_MESSAGE_MACROS_INCLUDE_BLOCK #endif
使用的时候
#define MESSAGES_INTERNAL_FILE "ipc/ipc_sync_message_unittest.h"
#include "ipc/ipc_message_macros.h"
unittest.h的内容
IPC_BEGIN_MESSAGES(Test)
IPC_SYNC_MESSAGE_CONTROL0_0(SyncChannelTestMsg_NoArgs)
IPC_END_MESSAGES(Test)
异步的使用
IPC_MESSAGE_CONTROL1(ProfileImportProcessMsg_ReportImportItemFinished,
int /* ImportItem */)
具体数据使用tuple包装
然后就能生成,既能保证唯一id,又能自动化生成这个相应类的代码了,看google代码,全是新东西,累
看完了message相关的,就要看ipc了,命名管道创建好后,会首先发送自己的进程号出去,这时用的是一个特殊类型HELLO_MESSAGE_TYPE的message,跟上面的那些无关了,毕竟是只用一次的
ipc的接受过程,跟一般的自定义协议的过程类似(创建一个大缓冲,收到的都读到这里去,然后根据包头大小提取完整包)
他这里的区别是读到另一个buffer里,没有直接往大缓冲里写,难道是为了多线程?但是他这里没有对多线程做任何保障
然后通知listener接受消息
ProcessIncomingMessages()
ReadFile(pipe_, input_buf_,
input_overflow_buf_.append(input_buf_, bytes_read);
这种处理方式无论如何效率也称不上高,估计是因为客户端的原因,google觉得无所谓吧
往外发消息,他用了一个队列output_queue_,然后往外发,这里是为了对出现ERROR_IO_PENDING的时候,简化了处理动作
留了一个时间来等待系统完成这个动作,但是下次再进来的时候如果还是没有发送完成,就报错了,这里pipe毕竟是本机上的,如果涉及到网络这肯定就不行了
驱动完全靠完成端口,这个还不了解,不过一套流程终于是完成了
来看个例子吧,browser端的render_view_host要获取个当前页面的缩略图,缩略图对应的消息是ViewMsg_Thumbnail 和ViewHostMsg_Thumbnail
然后browser会打包发送这个请求,通过ipc和picker中转序列反序列后,renderer收到命令,
IPC_MESSAGE_HANDLER(ViewMsg_CaptureThumbnail, OnCaptureThumbnail)
收到后,获取缩略图并发送回去
if (!CaptureThumbnail(webview(), kThumbnailWidth, kThumbnailHeight,
&thumbnail, &score))
return;
// send the thumbnail message to the browser process
Send(new ViewHostMsg_Thumbnail(routing_id_, url, score, thumbnail));
browser这段
IPC_MESSAGE_HANDLER(ViewHostMsg_Thumbnail, OnMsgThumbnail)
void RenderViewHost::OnMsgThumbnail(const GURL& url,
const ThumbnailScore& score,
const SkBitmap& bitmap) {
delegate_->UpdateThumbnail(url, bitmap, score);
}
可以看到这一套流程走的很方便,对开发者来说会使用这个太简单了
同步消息,他是依赖于发送后,等待消息过来时的event,
ChannelProxy::Send(message);
WaitForReply(context, pump_messages_event);
然后再能接收到消息的线程里判断消息是否有event,有的话,激活并分发
接受对象需要继承channel的listener,也是观察者模式