一、ipc与rpc通信概述
基本概念
ipc(inter-process communication)与rpc(remote procedure call)用于实现跨进程通信,不同的是前者使用binder驱动,用于设备内的跨进程通信,后者使用软总线驱动,用于跨设备跨进程通信。需要跨进程通信的原因是因为每个进程都有自己独立的资源和内存空间,其他进程不能随意访问不同进程的内存和资源,ipc/rpc便是为了突破这一点。ipc和rpc通常采用客户端-服务器(client-server)模型,在使用时,请求服务的(client)一端进程可获取提供服务(server)一端所在进程的代理(proxy),并通过此代理读写数据来实现进程间的数据通信,更具体的讲,首先请求服务的(client)一端会建立一个服务提供端(server)的代理对象,这个代理对象具备和服务提供端(server)一样的功能,若想访问服务提供端(server)中的某一个方法,只需访问代理对象中对应的方法即可,代理对象会将请求发送给服务提供端(server);然后服务提供端(server)处理接受到的请求,处理完之后通过驱动返回处理结果给代理对象;最后代理对象将请求结果进一步返回给请求服务端(client)。通常,server会先注册系统能力(system ability)到系统能力管理者(system ability manager,缩写samgr)中,samgr负责管理这些sa并向client提供相关的接口。client要和某个具体的sa通信,必须先从samgr中获取该sa的代理,然后使用代理和sa通信。下文直接使用proxy表示服务请求方,stub表示服务提供方。
约束与限制
● 单个设备上跨进程通信时,传输的数据量最大约为1mb,过大的数据量请使用匿名共享内存
● 不支持在rpc中订阅匿名stub对象(没有向samgr注册stub对象)的死亡通知。
● 不支持把跨设备的proxy对象传递回该proxy对象所指向的stub对象所在的设备,即指向远端设备stub的proxy对象不能在本设备内进行二次跨进程传递。
使用建议
首先,需要编写接口类,接口类中必须定义消息码,供通信双方标识操作,可以有未实现的的方法,因为通信双方均需继承该接口类且双方不能是抽象类,所以此时定义的未实现的方法必须在双方继承时给出实现,这保证了继承双方不是抽象类。然后,需要编写stub端相关类及其接口,并且实现asobject方法及onremoterequest方法。同时,也需要编写proxy端,实现接口类中的方法和asobject方法,也可以封装一些额外的方法用于调用sendrequest向对端发送数据。以上三者都具备后,便可以向samgr注册sa了,此时的注册应该在stub所在进程完成。最后,在需要的地方从samgr中获取proxy,便可通过proxy实现与stub的跨进程通信了。
相关步骤:
● 实现接口类:需继承iremotebroker,需定义消息码,可声明不在此类实现的方法。
● 实现服务提供端(stub):需继承iremotestub或者remoteobject,需重写asobject方法及onremoterequest方法。
● 实现服务请求端(proxy):需继承iremoteproxy或remoteproxy,需重写asobject方法,封装所需方法调用sendrequest。
● 注册sa:申请sa的唯一id,向samgr注册sa。
● 获取sa:通过sa的id和设备id获取proxy,使用proxy与远端通信
二、 ipc与rpc通信开发指导
场景介绍
ipc/rpc的主要工作是让运行在不同进程的proxy和stub互相通信,包括proxy和stub运行在不同设备的情况。
接口说明
表1 native侧ipc接口
类/接口 方法 功能说明
iremotebroker sptr asobject() 返回通信对象。stub端返回remoteobject对象本身,proxy端返回代理对象。
iremotestub virtual int onremoterequest(uint32_t code, messageparcel &data, messageparcel &reply, messageoption &option) 请求处理方法,派生类需要重写该方法用来处理proxy的请求并返回结果。
iremoteproxy remote()->sendrequest(code, data, reply, option) 消息发送方法,业务的proxy类需要从iremoteproxy类派生,该方法用来向对端发送消息。
开发步骤
native侧开发步骤
1. 添加依赖
sdk依赖:
#ipc场景external_deps = [ ipc:ipc_single,]#rpc场景external_deps = [ ipc:ipc_core,]
此外, ipc/rpc依赖的refbase实现在公共基础库下,请增加对utils的依赖:
external_deps = [ c_utils:utils,]
2.定义ipc接口itestability
sa接口继承ipc基类接口iremotebroker,接口里定义描述符、业务函数和消息码,其中业务函数在proxy端和stub端都需要实现。
#include iremote_broker.h//定义消息码const int trans_id_ping_ability = 5const std::string descriptor = test.itestability;class itestability : public iremotebroker {public: // declare_interface_descriptor是必需的,入参需使用std::u16string; declare_interface_descriptor(to_utf16(descriptor)); virtual int testpingability(const std::u16string &dummy) = 0; // 定义业务函数};
3.定义和实现服务端testabilitystub
该类是和ipc框架相关的实现,需要继承 iremotestub。stub端作为接收请求的一端,需重写onremoterequest方法用于接收客户端调用。
#include iability_test.h#include iremote_stub.hclass testabilitystub : public iremotestub {public: virtual int onremoterequest(uint32_t code, messageparcel &data, messageparcel &reply, messageoption &option) override; int testpingability(const std::u16string &dummy) override; };int testabilitystub::onremoterequest(uint32_t code, messageparcel &data, messageparcel &reply, messageoption &option){ switch (code) { case trans_id_ping_ability: { std::u16string dummy = data.readstring16(); int result = testpingability(dummy); reply.writeint32(result); return 0; } default: return ipcobjectstub::onremoterequest(code, data, reply, option); }}
4. 定义服务端业务函数具体实现类testability
#include iability_server_test.hclass testability : public testabilitystub {public: int testpingability(const std::u16string &dummy);}int testability::testpingability(const std::u16string &dummy) { return 0;}
5. 定义和实现客户端 testabilityproxy
该类是proxy端实现,继承iremoteproxy,调用sendrequest接口向stub端发送请求,对外暴露服务端提供的能力。
#include iability_test.h#include iremote_proxy.h#include iremote_object.hclass testabilityproxy : public iremoteproxy {public: explicit testabilityproxy(const sptr &impl); int testpingability(const std::u16string &dummy) override;private: static inline brokerdelegator delegator_; // 方便后续使用iface_cast宏}testabilityproxy::testabilityproxy(const sptr &impl) : iremoteproxy(impl){}int testabilityproxy::testpingability(const std::u16string &dummy){ messageoption option; messageparcel dataparcel, replyparcel; dataparcel.writestring16(dummy); int error = remote()- >sendrequest(trans_id_ping_ability, dataparcel, replyparcel, option); int result = (error == err_none) ? replyparcel.readint32() : -1; return result;}
6. sa注册与启动
sa需要将自己的testabilitystub实例通过addsystemability接口注册到systemabilitymanager,设备内与分布式的注册参数不同。
// 注册到本设备内auto samgr = systemabilitymanagerclient::getinstance().getsystemabilitymanager();samgr- >addsystemability(said, new testability());// 在组网场景下,会被同步到其他设备上auto samgr = systemabilitymanagerclient::getinstance().getsystemabilitymanager();isystemabilitymanager::saextraprop saextra;saextra.isdistributed = true; // 设置为分布式saint result = samgr- >addsystemability(said, new testability(), saextra);
7. sa获取与调用
通过systemabilitymanager的getsystemability方法可获取到对应sa的代理iremoteobject,然后构造testabilityproxy即可。
// 获取本设备内注册的sa的proxysptr samgr = systemabilitymanagerclient::getinstance().getsystemabilitymanager();sptr remoteobject = samgr- >getsystemability(said);sptr testability = iface_cast(remoteobject); // 使用iface_cast宏转换成具体类型// 获取其他设备注册的sa的proxysptr samgr = systemabilitymanagerclient::getinstance().getsystemabilitymanager();// networkid是组网场景下对应设备的标识符,可以通过getlocalnodedeviceinfo获取sptr remoteobject = samgr- >getsystemability(said, networkid);sptr proxy(new testabilityproxy(remoteobject)); // 直接构造具体proxy
js侧开发步骤
1. 添加依赖
import rpc from @ohos.rpcimport featureability from @ohos.ability.featureability
2.绑定ability
首先,构造变量want,指定要绑定的ability所在应用的包名、组件名,如果是跨设备的场景,还需要绑定目标设备networkid(组网场景下对应设备的标识符,可以使用devicemanager获取目标设备的networkid);然后,构造变量connect,指定绑定成功、绑定失败、断开连接时的回调函数;最后,使用featureability提供的接口绑定ability。
import rpc from @ohos.rpcimport featureability from @ohos.ability.featureabilitylet proxy = nulllet connectid = null// 单个设备绑定abilitylet want = { // 包名和组件名写实际的值 bundlename: ohos.rpc.test.server, abilityname: ohos.rpc.test.server.serviceability,}let connect = { onconnect:function(elementname, remote) { proxy = remote }, ondisconnect:function(elementname) { }, onfailed:function() { proxy = null }}connectid = featureability.connectability(want, connect)// 如果是跨设备绑定,可以使用devicemanager获取目标设备networkidimport devicemanager from '@ohos.distributedhardware.devicemanager'function devicemanagercallback(devicemanager) { let devicelist = devicemanager.gettrusteddevicelistsync() let networkid = devicelist[0].networkid let want = { bundlename: ohos.rpc.test.server, abilityname: ohos.rpc.test.service.serviceability, networkid: networkid, flags: 256 } connectid = featureability.connectability(want, connect)}// 第一个参数是本应用的包名,第二个参数是接收devicemanager的回调函数devicemanager.createdevicemanager(ohos.rpc.test, devicemanagercallback)
3.服务端处理客户端请求
服务端被绑定的ability在onconnect方法里返回继承自rpc.remoteobject的对象,该对象需要实现onremotemessagerequest方法,处理客户端的请求。
onconnect(want: want) { var robj:rpc.remoteobject = new stub(rpctestability) return robj}class stub extends rpc.remoteobject { constructor(descriptor) { super(descriptor) } onremotemessagerequest(code, data, reply, option) { // 根据code处理客户端的请求 return true }}
4.客户端处理服务端响应
客户端在onconnect回调里接收到代理对象,调用sendrequestasync方法发起请求,在期约(javascript期约:用于表示一个异步操作的最终完成或失败及其结果值)或者回调函数里接收结果。
// 使用期约let option = new rpc.messageoption()let data = rpc.messageparcel.create()let reply = rpc.messageparcel.create()// 往data里写入参数proxy.sendrequestasync(1, data, reply, option) .then(function(result) { if (result.errcode != 0) { console.error(send request failed, errcode: + result.errcode) return } // 从result.reply里读取结果 }) .catch(function(e) { console.error(send request got exception: + e) } .finally(() = > { data.reclaim() reply.reclaim() })// 使用回调函数function sendrequestcallback(result) { try { if (result.errcode != 0) { console.error(send request failed, errcode: + result.errcode) return } // 从result.reply里读取结果 } finally { result.data.reclaim() result.reply.reclaim() }}let option = new rpc.messageoption()let data = rpc.messageparcel.create()let reply = rpc.messageparcel.create()// 往data里写入参数proxy.sendrequest(1, data, reply, option, sendrequestcallback)
5.断开连接
ipc通信结束后,使用featureability的接口断开连接。
import rpc from @ohos.rpcimport featureability from @ohos.ability.featureabilityfunction disconnectcallback() { console.info(disconnect ability done)}featureability.disconnectability(connectid, disconnectcallback)
买手机不着急,小米6、三星S8、iphone7、华为mate9价格将在下半年跌到冰点!
强强联合量子保保险科技赋能无人机领域
亚马逊在加州使用无人送货机器人
中国移动完成业界首创5G智简本地网商用试点
华为专利在网络上浮出水面,该专利描述了带有不寻常相机的眼镜
HarmonyOS跨进程通信—IPC与RPC通信开发
华为P40系列核心供应商名单曝光 美系元器件库存仍然可支持其明年的需求
MP3游戏功能
揭开台湾晶圆代工双雄之争内幕
IBM z16推出全新的容量订阅模式
三星将在明年上半年正式推出折叠手机引领手机潮流
“5G+零碳+新能源+无人驾驶”智慧矿山起航
走进科技殿堂,唯样联合西安交大举办新能源电控培训会
感应加热技术应用于金属透热
丰田开路,视觉高精地图+众包“春天来了”
“AI+医疗”的三个层次和面临的挑战
德州仪器/晨星投入研发 MHL3.0或杀进中低端手机
新唐科技NUC029NAN主板简介
鸿蒙系统升级名单 鸿蒙系统百机升级计划
中国芯片真的来了!“魂芯二号A”震撼发布