一、权重计算公式
LNN的权重计算采用 设备类型基础权重 + 随机值 的组合方式:
最终权重 = 设备类型基础权重 + 随机值(0~1000)
二、设备类型基础权重表
| 设备类型 | 类型ID | 基础权重值 |
|---|---|---|
| TV(电视) | 0x9C | 8000 |
| Audio(音响) | 0x0A | 7000 |
| Car(车机) | 0x83 | 5000 |
| PC(电脑) | 0x04 | 4000 |
| Pad(平板) | 0x11 | 3000 |
| Phone(手机) | 0x0E | 2000 |
| 其他/未知 | 0x00 | 0 |
权重优先级:TV > Audio > Car > PC > Pad > Phone > 其他
三、权重生成代码解析
// 文件:lnn_node_weight.c
#define MAX_WEIGHT_VALUE 1000 // 随机值范围:0~1000
#define BASE_WEIGHT_PHONE_VALUE 2000 // 手机基础权重
#define BASE_WEIGHT_PAD_VALUE 3000 // 平板基础权重
#define BASE_WEIGHT_TV_VALUE 8000 // 电视基础权重
#define BASE_WEIGHT_AUDIO_VALUE 7000 // 音响基础权重
#define BASE_WEIGHT_CAR_VALUE 5000 // 车机基础权重
#define BASE_WEIGHT_PC_VALUE 4000 // PC基础权重
int32_t LnnGetLocalWeight(void)
{
static int32_t weight;
static bool isGenWeight = false; // 权重只生成一次
uint8_t randVal = 0;
if (isGenWeight) {
return weight; // 直接返回已生成的权重
}
// 1. 生成0~1000的随机数
if (SoftBusGenerateRandomArray(&randVal, sizeof(randVal)) != SOFTBUS_OK) {
return randVal; // 生成失败则返回随机值
}
weight = (int32_t)((randVal * MAX_WEIGHT_VALUE) / UINT8_MAX); // randVal/255 * 1000
// 2. 获取本机设备类型ID
int32_t localDevTypeId = 0;
(void)LnnGetLocalNumInfo(NUM_KEY_DEV_TYPE_ID, &localDevTypeId);
// 3. 根据设备类型添加基础权重
switch (localDevTypeId) {
case TYPE_PHONE_ID:
weight += BASE_WEIGHT_PHONE_VALUE; // +2000
break;
case TYPE_PAD_ID:
weight += BASE_WEIGHT_PAD_VALUE; // +3000
break;
case TYPE_TV_ID:
weight += BASE_WEIGHT_TV_VALUE; // +8000
break;
case TYPE_AUDIO_ID:
weight += BASE_WEIGHT_AUDIO_VALUE; // +7000
break;
case TYPE_CAR_ID:
weight += BASE_WEIGHT_CAR_VALUE; // +5000
break;
case TYPE_PC_ID:
weight += BASE_WEIGHT_PC_VALUE; // +4000
break;
default:
break; // 其他类型不加基础权重
}
isGenWeight = true; // 标记已生成
return weight;
}
四、各设备权重范围
| 设备类型 | 权重范围 |
|---|---|
| TV | 8000 ~ 9000 |
| Audio | 7000 ~ 8000 |
| Car | 5000 ~ 6000 |
| PC | 4000 ~ 5000 |
| Pad | 3000 ~ 4000 |
| Phone | 2000 ~ 3000 |
| 其他 | 0 ~ 1000 |
五、选举比较算法
int32_t LnnCompareNodeWeight(int32_t weight1, const char *masterUdid1,
int32_t weight2, const char *masterUdid2)
{
// 1. 首先比较权重
if (weight1 != weight2) {
return weight1 - weight2; // 差值为正:weight1更大;为负:weight2更大
}
// 2. 权重相同则比较UDID(字典序)
if (masterUdid1 == NULL || masterUdid2 == NULL) {
return weight1 - weight2;
}
return strcmp(masterUdid1, masterUdid2); // UDID小者优先
}
六、选举流程图

七、选举消息同步
// 同步选举消息给所有在线节点(除了skipNetworkId)
void SendElectMessageToAll(const char *skipNetworkId)
{
LIST_FOR_EACH_ENTRY(item, &g_netBuilder.fsmList, LnnConnectionFsm, node) {
if (skipNetworkId != NULL && strcmp(item->connInfo.peerNetworkId, skipNetworkId) == 0) {
continue; // 跳过指定节点
}
if (!IsNodeOnline(item->connInfo.peerNetworkId)) {
continue; // 只同步给在线节点
}
(void)SyncElectMessage(item->connInfo.peerNetworkId);
}
}
八、设计优点
| 优点 | 说明 |
|---|---|
| 设备类型优先 | TV、Audio等固定设备比手机等移动设备更适合作主节点 |
| 随机性避免冲突 | 同类型设备间通过随机值区分,避免同时选举 |
| UDID保底 | 权重和UDID都相同时,UDID字典序小的优先 |
| 最终一致性 | 所有节点通过消息同步,最终都会收敛到同一个主节点 |
九、典型选举场景
假设网络中有3个节点:
节点A (Phone): weight = 2000 + 500 = 2500
节点B (TV): weight = 8000 + 300 = 8300
节点C (Pad): weight = 3000 + 800 = 3800
选举结果:节点B (TV) 当选为主节点
因为:8300 > 3800 > 2500
核心设计思想:主节点选举算法综合考虑了设备稳定性(TV/Audio等固定设备更适合作为主节点)和公平性(同类型设备间通过随机数区分)。

373

被折叠的 条评论
为什么被折叠?



