OpenHarmony轻量系统服务管理|消息广播功能实例操作详解(二)

函数实现详解

修改topic的消费者
/*
    函数功能:修改topic的消费者
    函数参数:@iUnknown:统一的接口对象
             @topic:待修改的topic
             @oldConsumer:旧的消费者
             @newConsumer:新的消费者
    函数返回:修改成功 返回旧的消费者,修改失败 返回NULL
    函数描述:查询指定topic的关系,并获取订阅该topic的消费者链表。
             遍历消费者链表,若找到待修改的消费者对象,则更改为新的消费者,并返回旧的消费者。否则返回NULL
*/
static Consumer *ModifyConsumer(IUnknown *iUnknown, const Topic *topic, Consumer *oldConsumer, Consumer *newConsumer)
{
    //参数检查
    if (iUnknown == NULL || topic == NULL || oldConsumer == NULL || newConsumer == NULL) {
        return NULL;
    }
    //从统一的接口对象中获取PubSubImplement实例
    PubSubImplement *broadcast = GET_OBJECT(iUnknown, PubSubImplement, iUnknown);
    if (broadcast->feature == NULL || broadcast->feature->GetRelation == NULL) {
        return NULL;
    }
    //在修改消费者前,先查询topic是否存在
    Relation *relation = broadcast->feature->GetRelation(broadcast->feature, topic);
    if (relation == NULL) {
        //topic不存在,返回NULL
        return NULL;
    }//topic存在
    MUTEX_Lock(broadcast->feature->mutex);
    ConsumerNode *item = NULL;
    UTILS_DL_LIST_FOR_EACH_ENTRY(item, &relation->callbacks.node, ConsumerNode, node) {
        //遍历,查找与oldConsumer相等的ConsumerNode结点
        if (item->consumer->Equal(item->consumer, oldConsumer)) {
            //将旧的消费者改为新的消费者,并返回旧的消费者
            Consumer *older = item->consumer;
            item->consumer = newConsumer;
            MUTEX_Unlock(broadcast->feature->mutex);
            return older;
        }
    }
    MUTEX_Unlock(broadcast->feature->mutex);
    return NULL;
}
取消订阅
/*
    函数功能:解除指定消费者与topic的订阅关系
    函数参数:@iUnknown:统一的接口对象
             @topic:订阅的topic
             @consumer:消费者
    函数返回:找到该消费者 返回它,没找到 返回NULL
    函数描述:查询指定topic的关系,获取订阅该topic的消费者链表。
             遍历消费者链表,若找到指定的消费者,则删除它所属的结点,并返回被删除的消费者。
*/
static Consumer *Unsubscribe(IUnknown *iUnknown, const Topic *topic, const Consumer *consumer)
{
    //参数检查
    if (iUnknown == NULL || topic == NULL || consumer == NULL) {
        return NULL;
    }
    //从统一的接口对象中获取PubSubImplement实例
    PubSubImplement *broadcast = GET_OBJECT(iUnknown, PubSubImplement, iUnknown);
    if (broadcast->feature == NULL || broadcast->feature->GetRelation == NULL) {
        return NULL;
    }
    //在取消订阅前,先查询topic是否存在
    Relation *relation = broadcast->feature->GetRelation(broadcast->feature, topic);
    if (relation == NULL) {
        return NULL;
    }
    MUTEX_Lock(broadcast->feature->mutex);
    ConsumerNode *item = NULL;
    UTILS_DL_LIST_FOR_EACH_ENTRY(item, &relation->callbacks.node, ConsumerNode, node) {
        //遍历,查找与consumer相等的结点
        if (item->consumer->Equal(item->consumer, consumer)) {
            //将当前结点从双向链表中删除
            UtilsListDelete(&item->node);
            break;
        }
    }
    MUTEX_Unlock(broadcast->feature->mutex);
    //判断上面的遍历操作是正常结束还是因为break结束
    if (item == &relation->callbacks || item == NULL) {
        //callbacks是一张双向循环链表,此时item循环到头节点,说明是正常结束,即未找到该消费者
        //item为NULL
        return NULL;
    }
    //找到指定的consumer
    //返回旧的consumer
    Consumer *oldConsumer = item->consumer;
    //释放consumerNode
    SAMGR_Free(item);
    return oldConsumer;
}
向topic发布数据
//向订阅了指定topic的所有消费者发送数据,调用ImmediatelyPublish()函数
static BOOL Publish(IUnknown *iUnknown, const Topic *topic, uint8 *data, int16 len)
{
    //从统一的接口对象中获取PubSubImplement实例
    PubSubImplement *broadcast = GET_OBJECT(iUnknown, PubSubImplement, iUnknown);
    //获取广播功能对象
    PubSubFeature *feature = broadcast->feature;
    if (feature == NULL) {
        //该功能不存在,返回FALSE
        return FALSE;
    }
    //*(uint32 *)topic  将指向topic类型的指针转换为uint32类型,并取出指针指向的值,注:本质上topic类型就是uint32类型
    //构建MSG_PUBLISH类型的请求消息,消息值为topic。发送小消息时采用msgvalue,发送大消息时采用data缓冲区
    Request request = {MSG_PUBLISH, 0, NULL, *(uint32 *)topic};
    //若data不为NULL并且len大于0,则填充request的数据段
    if (data != NULL && len > 0) {
        //申请数据缓冲区,大小为len
        request.data = (uint8 *)SAMGR_Malloc(len);
        if (request.data == NULL) {
            //内存申请失败,返回false
            return FALSE;
        }
        //记录数据缓冲区的长度
        request.len = len;
        //拷贝数据缓冲区的内存
        (void)memcpy_s(request.data, request.len, data, len);
    }
    //判断数据是否发布成功,即向所有消费者发送请求数据是否成功
    if (!ImmediatelyPublish(feature, topic, &request)) {
        //发送失败,回收资源
        (void)SAMGR_Free(request.data);
        request.data = NULL;
        request.len = 0;
        return FALSE;
    }
    return TRUE;
}
向消费者发送数据
/*
    函数功能:向消费者发送数据
    函数参数:@feature:广播服务子功能对象
             @topic:指定的topic
             @request:待发送的请求数据
    函数返回:发送成功 返回TRUE,发送失败 返回FALSE
    函数描述:查询指定topic的订阅关系,获得消费者集合的链表。
             遍历消费者结点链表,向订阅了指定topic的所有消费者发送消息。
             若消费者绑定了身份标识则调用SAMGR_SendSharedDirectRequest()发送
             若消费者未绑定身份标识,则通过SAMGR_SendSharedRequest()发送
*/
static BOOL ImmediatelyPublish(PubSubFeature *feature, const Topic *topic, const Request *request)
{
    if (feature->GetRelation == NULL) {
        //未初始化,返回FALSE
        return FALSE;
    }
    //获取topic的关系
    Relation *relation = feature->GetRelation(feature, topic);
    if (relation == NULL) {
        //关系不存在返回false
        return FALSE;
    }
    //判断消费者结点链表是否为空,当链表中只有头结点时,链表判定为空
    if (UtilsListEmpty(&relation->callbacks.node)) {
        return FALSE;
    }
    //标识消息是否需要异步发送
    BOOL needAync = FALSE;
    ConsumerNode *item = NULL;
    uint32 *token = NULL;
    MUTEX_Lock(feature->mutex);
    //遍历消费者结点链表,向订阅了指定topic的所有消费者发送消息。
    //若消费者绑定了身份标识则调用SAMGR_SendSharedDirectRequest()发送
    //若消费者未绑定身份标识,则通过SAMGR_SendSharedRequest()发送
    UTILS_DL_LIST_FOR_EACH_ENTRY(item, &relation->callbacks.node, ConsumerNode, node) {
        if (item->consumer->identity == NULL) {
            //若存在消费者未绑定身份标识,则记录需要异步发送
            needAync = TRUE;
            continue;
        }
        //向绑定了身份标识的消费者直接发送消息
        //创建回复消息
        Response response = {item->consumer, 0};
        //发送调用者的请求和响应。直接调用DefaultHandle来处理请求和响应,而不使用消息处理函数。
        int ret = SAMGR_SendSharedDirectRequest(item->consumer->identity, request, &response, &token, DefaultHandle);
        if (ret != EC_SUCCESS) {
            //发送失败,结束循环
            needAync = FALSE;
            break;
        }
    }
    if (needAync) {
        //向指定identity发送请求以节省内存。用于为Broadcast服务发布主题,以广播消息。
        token = SAMGR_SendSharedRequest(&feature->identity, request, token, NULL);
    }
    MUTEX_Unlock(feature->mutex);
    return (token != NULL);
}
默认的消息处理函数
/*
    函数功能:默认的消息处理函数
    函数参数:@request:请求消息
             @response:响应消息
    函数描述:通过抢占全局广播功能的锁来判断消息发布操作是否已完成。
             若成功抢到锁则说明消息已发布完成,可以对消息进行处理。
             通知指定的消费者对该topic中发布的消息数据进行处理。
*/
static void DefaultHandle(const Request *request, const Response *response)
{
    //获取response中存储的consumer
    Consumer *consumer = (Consumer *)response->data;
    if (consumer == NULL || consumer->Notify == NULL || g_pubSubImplement.feature == NULL) {
        return;
    }
    //通过抢占锁来判断ImmediatelyPublish()是否已完成
    //若没抢到,则阻塞,等待锁被释放重新抢占
    MUTEX_Lock(g_pubSubImplement.feature->mutex);
    //抢占成功,代表ImmediatelyPublish()已完成
    MUTEX_Unlock(g_pubSubImplement.feature->mutex);
    //获取request中传输的消息值,这里是topic的值
    Topic topic = request->msgValue;
    //处理topic中已发布的数据
    consumer->Notify(consumer, &topic, request);
}

总是有很多小伙伴反馈说:OpenHarmony开发不知道学习哪些技术?不知道需要重点掌握哪些OpenHarmony开发知识点? 为了解决大家这些学习烦恼。在这准备了一份很实用的鸿蒙全栈开发学习路线与学习文档给大家用来跟着学习。

针对一些列因素,整理了一套纯血版鸿蒙(HarmonyOS Next)全栈开发技术的学习路线,包含了鸿蒙开发必掌握的核心知识要点,内容有(OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、OpenHarmony驱动开发、系统定制移植……等)技术知识点。

OpenHarmony 开发环境搭建:https://gitcode.com/HarmonyOS_MN/733GH/overview


在这里插入图片描述

《OpenHarmony源码解析》

搭建开发环境
系统架构分析

  • 构建子系统
  • 启动流程
  • 子系统
  • 分布式任务调度子系统
  • 分布式通信子系统
  • 驱动子系统
  • ……

OpenHarmony 设备开发学习手册:https://gitcode.com/HarmonyOS_MN

在这里插入图片描述

鸿蒙开发面试真题(含参考答案):https://gitcode.com/HarmonyOS_MN/733GH/overview

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值