一、前言
本文针对message中的相关函数的实现进行分析,相应的文件位于distributedschedule_samgr_lite\samgr\source\message.c。本部分消息通信的过程是基于消息队列来实现的,穿插了大量的消息队列操作,消息传递的对象是exchange,内部包含了request和response。
二、实现分析
- 结构体分析
//传递消息时的结构体
struct Exchange {
//目标服务或特性标识
Identity id;
//请求消息
Request request;
//响应消息
Response response;
//消息的类型
short type;
//异步响应或回调函数
Handler handler;
//用于共享请求和响应的引用计数
uint32 *sharedRef;
};
- 函数实现分析
发送请求操作
/*
函数功能:发送请求消息
函数参数:@identity:标识服务或特性的ID
@request:请求消息
@handler:消息的响应处理函数
函数返回:成功返回EC_SUCCESS,失败返回EC_INVALID or EC_BUSBUSY
函数描述:根据参数创建消息交换对象exchange,exchange对象是消息传递的载体。
将消息放入identity标识的消息队列中,完成消息的发送。
在消息传输前判断该消息是否指定回调函数handler。
若未指定,则在处理这条消息时不需要发送响应。若指定,则在处理完该消息后需要发送响应。
所以将当前线程绑定的消息队列ID赋给exchange对象的queueId,处理完消息后将响应消息发送到当前线程的消息队列中。
*/
int32 SAMGR_SendRequest(const Identity *identity, const Request *request, Handler handler)
{
//参数检查
if (request == NULL || identity == NULL) {
return EC_INVALID;
}
//创建exchange对象,用于传递消息,将请求消息放到指定的消息队列中
Exchange exchange = {*identity, *request, {NULL, 0}, MSG_NON, handler, NULL};
exchange.id.queueId = NULL;
if (handler != NULL) {
//handler不为NULL,即消息有响应处理函数
//获取当前的线程绑定的消息队列ID,这里的消息队列ID是线程创建时绑定的。
//当消息的处理者处理完消息并进行响应时,将响应消息对象发送到当前线程的消息队列中。
exchange.id.queueId = SAMGR_GetCurrentQueueID();
//类型表示当处理完消息需要发送响应给当前线程
exchange.type = MSG_CON;
}//若handler为NULL,则当前消息对象不存在消息的响应处理,类型为MSG_NON
//将请求放入队列,消息的处理需要调用对应的服务或功能的消息处理函数。
return QUEUE_Put(identity->queueId, &exchange, 0, DONT_WAIT);
}
发送响应操作
/*
函数功能:发送响应消息
函数参数:@request:请求消息
@response:响应消息
函数返回:成功返回EC_SUCCESS,失败返回EC_INVALID
函数描述:针对MSG_CON类型的消息发送响应。
若消息的响应处理函数handler==NULL,则不需要处理。
若不为空,则判断exchange->id.queueId的值,若为NULL,则无需发送到消息响应队列中,直接调用响应处理函数处理。
若exchange->id.queueId不为空,则将消息类型更新为MSG_ACK,然后发送到queueId中,由queueId对应的线程进行处理,这样exchange对象就由多个消息队列共享。
*/
int32 SAMGR_SendResponse(const Request *request, const Response *response)
{
//参数检查
if (request == NULL) {
return EC_INVALID;
}
//获取exchange对象
Exchange *exchange = GET_OBJECT(request, Exchange, request);
if (exchange->type != MSG_CON) {
//类型不是MSG_CON,则不发送响应,返回EC_INVALID
return EC_INVALID;
}
if (exchange->handler == NULL) {
//消息的响应处理函数==NULL,则不需要发送响应,返回EC_SUCCESS
return EC_SUCCESS;
}
//消息类型为MSG_CON,消息响应函数不为NULL
//更新当前消息类型为MSG_ACK确认
exchange->type = MSG_ACK;
//初始化响应数据
exchange->response.data = NULL;
exchange->response.len = 0;
if (response != NULL) {
exchange->response = *response;
}
//如果没有任务队列,则调用当前任务中的响应处理器。这里的队列是通过SAMGR_GetCurrentQueueID()获得的
if (exchange->id.queueId == NULL) {
exchange->handler(&exchange->request, &exchange->response);
return EC_SUCCESS;
}
//如果队列ID不为空,则调用sharedsend(),将消息对象放入指定的消息队列中(发送回原来的队列中),由它对应的线程进行处理。
//此时的exchange对象是共享的,即被两个或以上的消息队列引用
int32 ret = SharedSend(exchange->id.queueId, exchange, 1);
//如果队列已满,则直接调用消息的响应处理函数
if (ret != EC_SUCCESS) {
//不成功则调用当前任务中的响应处理器
exchange->handler(&exchange->request, &exchange->response);
//更新引用
(void)FreeReference(exchange);
}
return EC_SUCCESS;
}
接收消息操作
/*
函数功能:从消息队列接收消息
函数描述:从指定的消息队列中读取size大小的数据,拷贝到interMsg中。该操作为阻塞IO
*/
int32 SAMGR_MsgRecv(MQueueId queueId, uint8 *interMsg, uint32 size)
{
//参数检查
if (queueId == NULL || interMsg == NULL || size == 0) {
return EC_INVALID;
}
//将interMsg清空
if (memset_s(interMsg, size, 0x00, size) != EOK) {
return EC_FAILURE;
}
//消息出队,阻塞操作,直到出队成功
return QUEUE_Pop(queueId, interMsg, 0, WAIT_FOREVER);
}
总是有很多小伙伴反馈说:OpenHarmony开发不知道学习哪些技术?不知道需要重点掌握哪些OpenHarmony开发知识点? 为了解决大家这些学习烦恼。在这准备了一份很实用的鸿蒙全栈开发学习路线与学习文档给大家用来跟着学习。
针对一些列因素,整理了一套纯血版鸿蒙(HarmonyOS Next)全栈开发技术的学习路线,包含了鸿蒙开发必掌握的核心知识要点,内容有(OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、OpenHarmony驱动开发、系统定制移植……等)技术知识点。
OpenHarmony 开发环境搭建:https://gitcode.com/HarmonyOS_MN/733GH/overview
《OpenHarmony源码解析》
搭建开发环境
系统架构分析
- 构建子系统
- 启动流程
- 子系统
- 分布式任务调度子系统
- 分布式通信子系统
- 驱动子系统
- ……