chrome-IPC简介

以下知识点是比较凌乱的,后续整理:以下代码均取自chromium34前期版本

channel监听+处理

因为chrome的base库和IPC代码是比较小的,所以使用chrome做IPC封装
chrome是使用有名管道来进行通讯:
参看:src\ipc\ipc_channel_win.cc

bool Channel::ChannelImpl::CreatePipe(const IPC::ChannelHandle &channel_handle,
                                      Mode mode) {
bool Channel::ChannelImpl::ProcessConnection() {
 ....
  BOOL ok = ConnectNamedPipe(pipe_, &input_state_.context.overlapped);

从上述代码可以看出,chrome使用了Channel类来封装了有名管道, Channel的基类如下:

class Channel::ChannelImpl : public internal::ChannelReader,
                             public MessageLoopForIO::IOHandler {
-->
typedef base::MessagePumpForIO::IOHandler IOHandler;
-->
ChannelReader::ChannelReader(Channel::Listener* listener)

channel通过两个基类可以实现以下功能:
1.Listener处理接收到的具体实现,具体由Channel的使用者来实现
2.MessagePumpForIO::IOHandler即IO完成端口,调用者只有把IO对象的句柄交给MessageLoopForIO对象(MessagePumpForIO ::RegisterIOHandler),以后每当有IO对象的操作完成时,调用者就会从MessageLoopForIO收到回调通知(IOHandler::OnIOCompleted), 相当于watcher
即channel 可以在消息到来时IOHandler收到回调,并调用listener处理

只有一个线程操作channel,即IO线程

ChannelProxy跨线程发送

前面提到了,操作 channel的总是IO线程,但基本上我们都是需要从非IO线程与其他进程通讯,chrome最擅长的是什么? task,对的,把对 channel的操作放在task中,再把task post到IO线程队列中,chrome封装了一个代理层ipc\ipc_channel_proxy.h

class IPC_EXPORT ChannelProxy : public Message::Sender {

它的基类是Message::Sender,也就是它是发送者,结合上面的watcher、listener,完整的链条形成了
它是通过以下函数把消息PostTask到IO线程

bool ChannelProxy::Send(Message* message) {
 ...
  context_->ipc_message_loop()->PostTask(
      FROM_HERE,
      base::Bind(&ChannelProxy::Context::OnSendMessage,
                 context_, base::Passed(scoped_ptr<Message>(message))));
  return true;
}
---->
// Called on the IPC::Channel thread
void ChannelProxy::Context::OnSendMessage(scoped_ptr<Message> message) {
  if (!channel_.get()) {
    OnChannelClosed();
    return;
  }
  if (!channel_->Send(message.release()))
    OnChannelError();
}

如果要发同步消息,使用SyncChannel,它其实是在ChannelProxy的基础上增加一个等待,不过为什么不叫SyncChannelProxy呢?

class IPC_EXPORT SyncChannel : public ChannelProxy,
public base::WaitableEventWatcher::Delegate {

ChannelProxy的构造如下:

// Initializes a channel proxy. The channel_handle and mode parameters are
// passed directly to the underlying IPC::Channel. The listener is called on
// the thread that creates the ChannelProxy. The filter's OnMessageReceived
// method is called on the thread where the IPC::Channel is running. The
// filter may be null if the consumer is not interested in handling messages
// on the background thread. Any message not handled by the filter will be
// dispatched to the listener. The given message loop indicates where the
// IPC::Channel should be created.
ChannelProxy(const IPC::ChannelHandle& channel_handle,
Channel::Mode mode,
Channel::Listener* listener,
base::MessageLoopProxy* ipc_thread_loop);

注意第四个参数,它允许我们自己实现MessageLoopProxy的子类,来转发消息到自己创建的线程中

消息宏

chrome的消息分两类,路由(routed)和控制(control),路由消息是私密的,系统会依照路由信息将消息安全的传递到目的地,不容它人窥视;控制消息就是一个广播消息,谁想听等能够听得到。所以外部封装直接使用control消息,chrome的消息宏展开是反人类的,它允许定义一次宏,展开多段代码,所以没有#pragma once,以下是DM使用的IPC消息定义:

#include "ipc/ipc_message_macros.h"
#define IPC_MESSAGE_START ChannelMsgStart

IPC_STRUCT_BEGIN(ChannelMsg_MessageContent)
    IPC_STRUCT_MEMBER(std::vector<unsigned char>, body)
    IPC_STRUCT_MEMBER(bool, reply_flag) // 回应标志,是否为应答消息
    IPC_STRUCT_MEMBER(int32, reply_id)  // 同步序号
    IPC_STRUCT_END()

    /// <summary>
    ///     客户端请求服务端代理为其分配一个服务者,并返回服务者的名称 
    /// </summary>
    IPC_SYNC_MESSAGE_CONTROL0_1(ChannelMsg_ClientHostRequestService, std::string)

    /// <summary>
    ///     客户端向服务端查询管道ID 
    /// </summary>
    IPC_SYNC_MESSAGE_CONTROL0_1(ChannelMsg_ClientQueryId,int32)

    /// <summary>
    ///     CONTROL消息
    /// </summary>
    IPC_MESSAGE_CONTROL2(ChannelMsg_RoutingMessage, int32,  // target/sender host id
    ChannelMsg_MessageContent)
#define IPC_MESSAGE_IMPL
#include "IPC_MsgCrack.h"

// Generate constructors.
#include "ipc/struct_constructor_macros.h"
#include "IPC_MsgCrack.h"

// Generate destructors.
#include "ipc/struct_destructor_macros.h"
#include "IPC_MsgCrack.h"

// Generate param traits write methods.
#include "ipc/param_traits_write_macros.h"
namespace IPC 
{
#include "IPC_MsgCrack.h"
}// namespace IPC

// Generate param traits read methods.
#include "ipc/param_traits_read_macros.h"
namespace IPC 
{
#include "IPC_MsgCrack.h"
}// namespace IPC

SYNC表示同步调用,Send在等到回复时才返回,0_1表示0 in,1 out
eg:ChannelMsg_ClientQueryId,表示out一个int32(查询到的channel id)

更多细节可以参看ipc\ipc_message_macros.h

ChannelProxy::MessageFilter提前拦截消息

接收消息的函数,默认是IPC::Channel::Listener->OnMessageReceived函数,类似于MFC的Map机制,但是,我们可设置filter拦截消息,如果filter拦截并处理某个消息,就不会走到IPC::Channel::Listener->OnMessageReceived

  class IPC_EXPORT MessageFilter
      : public base::RefCountedThreadSafe<MessageFilter, MessageFilterTraits> {
    ....
    // Return true to indicate that the message was handled, or false to let
    // the message be handled in the default way.
    virtual bool OnMessageReceived(const Message& message);

设置filter使用
·
// Ordinarily, messages sent to the ChannelProxy are routed to the matching
// listener on the worker thread. This API allows code to intercept messages
// before they are sent to the worker thread.
// If you call this before the target process is launched, then you're
// guaranteed to not miss any messages. But if you call this anytime after,
// then some messages might be missed since the filter is added internally on
// the IO thread.
void AddFilter(MessageFilter* filter);
void RemoveFilter(MessageFilter* filter);

后续补充

参考:

http://blog.csdn.net/qhh_qhh/article/details/49077579
http://blog.csdn.net/farrellcn/article/details/51088936

猜你喜欢

转载自blog.csdn.net/hgy413/article/details/78943236
IPC