<acronym id="s8ci2"><small id="s8ci2"></small></acronym>
<rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
<acronym id="s8ci2"></acronym>
<acronym id="s8ci2"><center id="s8ci2"></center></acronym>
0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

HarmonyOS跨進程通信—IPC與RPC通信開發

王程 ? 來源: jf_75796907 ? 作者: jf_75796907 ? 2024-02-02 17:47 ? 次閱讀

一、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表示服務提供方。

wKgaomW8uiqAZmEVAAAZ1j7EkEI957.pngwKgZomUT3jGAEdeHAAAZ1j7EkEI286.png

約束與限制

? ● 單個設備上跨進程通信時,傳輸的數據量最大約為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 = 5

const 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.h"

class 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.h"

class 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.h"

class 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; // 設置為分布式SA
int result = samgr->AddSystemAbility(saId, new TestAbility(), saExtra);

? 7. SA獲取與調用

通過SystemAbilityManager的GetSystemAbility方法可獲取到對應SA的代理IRemoteObject,然后構造TestAbilityProxy即可。

// 獲取本設備內注冊的SA的proxy
sptr samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
sptr remoteObject = samgr->GetSystemAbility(saId);
sptr testAbility = iface_cast(remoteObject); // 使用iface_cast宏轉換成具體類型

// 獲取其他設備注冊的SA的proxy
sptr samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();

// networkId是組網場景下對應設備的標識符,可以通過GetLocalNodeDeviceInfo獲取
sptr remoteObject = samgr->GetSystemAbility(saId, networkId);
sptr proxy(new TestAbilityProxy(remoteObject)); // 直接構造具體Proxy

JS側開發步驟

? 1. 添加依賴

import rpc from "@ohos.rpc"
import featureAbility from "@ohos.ability.featureAbility"

2.綁定Ability

首先,構造變量want,指定要綁定的Ability所在應用的包名、組件名,如果是跨設備的場景,還需要綁定目標設備NetworkId(組網場景下對應設備的標識符,可以使用deviceManager獲取目標設備的NetworkId);然后,構造變量connect,指定綁定成功、綁定失敗、斷開連接時的回調函數;最后,使用featureAbility提供的接口綁定Ability。

import rpc from "@ohos.rpc"
import featureAbility from "@ohos.ability.featureAbility"

let proxy = null
let connectId = null

// 單個設備綁定Ability
let 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獲取目標設備NetworkId
import 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.rpc"
import featureAbility from "@ohos.ability.featureAbility"
function disconnectCallback() {
    console.info("disconnect ability done")
}
featureAbility.disconnectAbility(connectId, disconnectCallback)


審核編輯 黃宇

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • RPC
    RPC
    +關注

    關注

    0

    文章

    102

    瀏覽量

    11445
  • IPC
    IPC
    +關注

    關注

    3

    文章

    314

    瀏覽量

    51402
  • 鴻蒙
    +關注

    關注

    55

    文章

    1919

    瀏覽量

    42197
  • HarmonyOS
    +關注

    關注

    79

    文章

    1912

    瀏覽量

    29455
收藏 人收藏

    評論

    相關推薦

    鴻蒙OS跨進程IPCRPC通信

    一、IPCRPC通信概述 基本概念 IPC(Inter-Process Communication)與RPC(Remote Procedu
    發表于 02-17 14:20

    linux操作系統下的進程通信設計

    通信方面的側重點有所不同。前者對Unix早期的進程通信手段進行了系統的改進和擴充,形成了“system V IPC”,通信
    發表于 04-16 09:17

    【Linux學習雜談】之進程通信

    我們詳細看下進程通信大致分為以下幾個方面: Linux進程通信的幾種機制:(1)無名管道和有名管道(2)system V IPC 信號
    發表于 10-15 14:45

    HarmonyOS教程—基于分布式能力和IDL跨進程通信,實現視頻跨設備播放、控制

    。如何使用HarmonyOS IDL跨進程通信實現遠程控制視頻播放。技能要求HarmonyOS Player接口熟練使用基本組件熟練使用2. 搭建H
    發表于 09-13 11:49

    【中秋國慶不斷更】HarmonyOS跨進程通信IPCRPC通信開發指導

    一、IPCRPC通信概述 基本概念 IPC(Inter-Process Communication)與RPC(Remote Procedu
    發表于 09-27 15:48

    linux操作系統下的進程通信

    的側重點有所不同。前者對Unix早期的進程通信手段進行了系統的改進和擴充,形成了system V IPC,通信進程局限在單個計算機內;后者
    發表于 10-31 11:15 ?0次下載

    如何實現進程間的通信IPC)?

    1、管道( pipe ) 既可在程序中使用,也可在shell中使用。 管道是一種半雙工的通信方式,數據只能單向流動。 管道的問題在于他們沒有名字,只能在具有親緣關系(父子進程間)的進程間使用。 擴展
    發表于 11-29 13:33 ?8992次閱讀

    Linux系統中的進程之間通信

    六、總結 一、Linux 系統中的進程之間通信IPC)作為一名嵌入式軟件開發人員來說,處理進程之間的
    的頭像 發表于 04-12 10:06 ?4421次閱讀
    Linux系統中的<b class='flag-5'>進程</b>之間<b class='flag-5'>通信</b>

    Linux進程間的五種通信方式介紹 1

    進程通信IPC,InterProcess Communication)是指在不同進程之間傳播或交換信息。IPC的方式通常有管道(包括無名
    的頭像 發表于 02-15 10:18 ?1177次閱讀
    Linux<b class='flag-5'>進程</b>間的五種<b class='flag-5'>通信</b>方式介紹 1

    Linux進程間的五種通信方式介紹 2

    進程通信IPC,InterProcess Communication)是指在不同進程之間傳播或交換信息。IPC的方式通常有管道(包括無名
    的頭像 發表于 02-15 10:19 ?376次閱讀
    Linux<b class='flag-5'>進程</b>間的五種<b class='flag-5'>通信</b>方式介紹 2

    Linux進程間的五種通信方式介紹 3

    進程通信IPC,InterProcess Communication)是指在不同進程之間傳播或交換信息。IPC的方式通常有管道(包括無名
    的頭像 發表于 02-15 10:19 ?367次閱讀

    Linux進程間的五種通信方式介紹 4

    進程通信IPC,InterProcess Communication)是指在不同進程之間傳播或交換信息。IPC的方式通常有管道(包括無名
    的頭像 發表于 02-15 10:19 ?439次閱讀

    Linux進程間的五種通信方式介紹 6

    進程通信IPC,InterProcess Communication)是指在不同進程之間傳播或交換信息。IPC的方式通常有管道(包括無名
    的頭像 發表于 02-15 10:19 ?330次閱讀

    Linux進程間的五種通信方式介紹 5

    進程通信IPC,InterProcess Communication)是指在不同進程之間傳播或交換信息。IPC的方式通常有管道(包括無名
    的頭像 發表于 02-15 10:20 ?437次閱讀

    進程通信的機制有哪些

    進程通信(interprocess communication,簡稱IPC)指兩個進程之間的通信。系統中的每一個
    的頭像 發表于 07-21 11:23 ?699次閱讀
    <b class='flag-5'>進程</b>間<b class='flag-5'>通信</b>的機制有哪些
    亚洲欧美日韩精品久久_久久精品AⅤ无码中文_日本中文字幕有码在线播放_亚洲视频高清不卡在线观看
    <acronym id="s8ci2"><small id="s8ci2"></small></acronym>
    <rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
    <acronym id="s8ci2"></acronym>
    <acronym id="s8ci2"><center id="s8ci2"></center></acronym>