采用AsyncIpc这个项目(https://github.com/hicdre/AsyncIpc),来完成PPAPI Plugin进程与Browser进程的通信。
foruok原创,如需转载请关注foruok的微信订阅号“程序视界”联系foruok。
AsyncIpc的IPC实现基于管道,是参考Chromium的IPC代码而来,适用于Windows。Chromium在Render和Browser进程间就使用类似的IPC机制,每一个Render都会与Browser建立一个双向的Channel。AsyncIpc采用类似的概念,抽象了Channel用于进程间通信。
基本用法
介绍下怎么集成AsyncIpc以及关键的类库。
引入方式
AsyncIpc可以编译为静态库和动态库。根据需要,也可以直接把源码加入到项目中。
类库
AyncIpc定义了一个名字空间IPC。IPC::EndPoint代表一个接入点,使用时需要创建一个接入点。当有对端进程接入时,EndPoint会发送一些通知,这些通知通过IPC::Listener接口发送,所以,实现Listener接口即可。
EndPoint类的构造函数原型如下:
Endpoint(const std::string& name, Listener* listener, bool start_now);
它需要一个Listener,所以我们需要先实现Listener接口。IPC::Listener定义如下:
class Listener {
public:
// Called when a message is received. Returns true iff the message was
// handled.
virtual bool OnMessageReceived(Message* message) = 0;
// Called when the channel is connected and we have received the internal
// Hello message from the peer.
virtual void OnChannelConnected(int32 peer_pid) {}
// Called when an error is detected that causes the channel to close.
// This method is not called when a channel is closed normally.
virtual void OnChannelError() {}
protected:
virtual ~Listener() {}
};
我们从Listener派生的类,实现OnMessageReceived、OnChannelConnected、OnChannelError三个方法即可处理IPC消息和状态。
那现在我们只需要一行代码就可以创建一个接入点等待连接了:
m_endPoint = new IPC::Endpoint("ppapi_ipc", this);
注意this指针代表的类实现了IPC::Listener接口,类声明如下:
class IPCImageClient : public IPC::Listener
{
public:
IPCImageClient();
virtual bool OnMessageReceived(IPC::Message* msg);
virtual void OnChannelConnected(int32 peer_pid);
virtual void OnChannelError();
private:
void SendRawImage();
void SendDecodedImage();
protected:
int m_peerPid;
IPC::Endpoint *m_endPoint;
};
而发送消息、接收或处理消息,就要用到Message类。发送消息的代码类似下面:
scoped_ref_ptr<IPC::Message> msg(new IPC::Message(GetCurrentProcessId(), 101, (IPC::Message::PriorityValue)0));
msg->WriteBytes(data, size);
m_endPoint->Send(msg.get());
接收消息的代码类似这样:
bool IPCImageClient::OnMessageReceived(IPC::Message* msg)
{
uint32 type = msg->type();
switch (type)
{
case 1: // data was consumed,write again
OutputDebugString(_T("SendImage to plugin\r\n"));
SendDecodedImage();
break;
}
return true;
}
或者这样:
bool IPCSimpleClient::OnMessageReceived(IPC::Message* msg)
{
const void *data = msg->payload();;
unsigned int len = msg->payload_size();
UIImage *imageView = (UIImage*)m_view;
uint32 type = msg->type();
switch (type)
{
case 100: // decoded image data
{
OutputDebugString(_T("received decoded image\r\n"));
SkBitmap received;
SkImageInfo info = SkImageInfo::Make(1280, 720,
kBGRA_8888_SkColorType, kPremul_SkAlphaType,
kLinear_SkColorProfileType);
received.installPixels(info, (void*)data, info.minRowBytes());
imageView->cloneBitmapFrom(received);
imageView->requestPaint(NULL);
}
break;
...
}
}
总结一下,使用AsyncIpc的步骤如下:
- 实现IPC::Listener接口
- 创建IPC::EndPoint对象,传递Listener接口给它
- 当连接建立后,发送消息(可以在OnChannelConnected方法中)
- 在Listener::OnMessageReceived方法中处理消息
就这样吧。
其他参考文章:
- CEF Windows开发环境搭建
- CEF加载PPAPI插件
- VS2013编译最简单的PPAPI插件
- 理解PPAPI的设计
- PPAPI插件与浏览器的交互过程
- Windows下从源码编译CEF
- 编译PPAPI的media_stream_video示例
- PPAPI插件的绘图与输入事件处理
- 在PPAPI插件中创建本地窗口
- PPAPI插件与浏览器的通信
- Windows下从源码编译Skia
- 在PPAPI插件中使用Skia绘图
- 加载DLL中的图片资源生成Skia中的SkBitmap对象
- PPAPI+Skia实现的涂鸦板
- PPAPI中使用Chromium的3D图形接口
- PPAPI中使用OpenGL ES绘图
- CEF中JS与C++交互
- CEF中Browser进程与Render进程间通信
- Chromium与CEF的多进程模型及相关参数