嵌入式设备网络的动态ID分配机制实现

news2025/4/21 2:54:17

文章目录

  • 前言
  • 一、系统设计要点
  • 二、核心数据结构
    • 2.1 设备唯一标识(DeviceUID)
    • 2.2 节点信息(Node)
    • 2.3 节点管理器(NodeManager)
  • 三、核心算法实现
    • 3.1 初始化与清理
      • 3.1.1 初始化节点管理器
      • 3.1.2 清理节点管理器
    • 3.2 动态ID分配策略
      • 3.2.1 查找最小可用ID
      • 3.2.2 ID使用检查
    • 3.3 心跳处理机制
    • 3.4 超时检测机制
  • 四、节点查找与管理
    • 4.1 通过UID查找节点
    • 4.2 通过ID查找节点
    • 4.3 获取活跃节点列表
  • 五、回调机制实现
    • 5.1 回调函数注册
    • 5.2 示例回调函数
  • 六、应用示例
  • 七、总结


前言

在嵌入式设备网络中,节点的动态加入与退出是常态,尤其是在无人机、传感器网络、智能家居等系统中,节点通常无法提前预设 ID,这就要求系统具备动态 ID 分配与管理能力。本篇博客将围绕“动态 ID 管理”这一核心,介绍一个基于设备 UID 的动态 ID 分配系统,支持重复上线检测、最小可用 ID 分配、ID 冲突检测、ID 释放与复用等功能,代码完全由 C 语言实现,结构清晰,易于移植与扩展。


一、系统设计要点

该系统以节点唯一标识符 DeviceUID 为基础,实现了以下关键特性:

  • 动态 ID 分配:无需提前为设备分配 ID,系统自动为新设备分配最小可用 ID。

  • UID 唯一识别机制:通过对 UID 的比较实现节点重复检测与状态更新。

  • ID 冲突检测:避免多个设备使用相同 ID 导致状态混乱。

  • ID 释放与复用:支持节点主动释放 ID,或超时后自动回收,以复用资源。

  • 回调机制:支持注册上线、下线回调函数,便于系统业务集成。

  • 心跳检测:通过心跳机制维护节点活跃状态

  • 超时处理:自动检测并清理离线节点

二、核心数据结构

2.1 设备唯一标识(DeviceUID)

typedef struct {
    uint8_t bytes[6];  // 6字节的唯一设备标识
} DeviceUID;

这个结构体用于存储设备的唯一标识符,通常可以是MAC地址或其他硬件唯一ID。

2.2 节点信息(Node)

typedef struct Node {
    uint8_t id;          // 分配的节点ID
    DeviceUID uid;       // 设备唯一标识
    uint64_t lastSeenMs; // 最后活跃时间戳(毫秒)
    struct Node* next;   // 下一个节点指针
} Node;

每个节点包含分配的ID、设备唯一标识、最后活跃时间和指向下一个节点的指针。

2.3 节点管理器(NodeManager)

typedef struct {
    Node* head;                  // 链表头指针
    uint8_t activeCount;         // 活跃节点计数
    NodeOnlineCallback onOnline; // 节点上线回调函数
    NodeOfflineCallback onOffline; // 节点下线回调函数
} NodeManager;

节点管理器维护所有活跃节点的链表,并提供回调函数接口。

三、核心算法实现

3.1 初始化与清理

3.1.1 初始化节点管理器

void NodeManager_Init(NodeManager* manager) {
    manager->head = NULL;
    manager->activeCount = 0;
    manager->onOnline = NULL;
    manager->onOffline = NULL;
}

3.1.2 清理节点管理器

void NodeManager_Cleanup(NodeManager* manager) {
    Node* current = manager->head;
    while (current) {
        Node* next = current->next;
        
        // 回调通知节点离线
        if (manager->onOffline) {
            manager->onOffline(current->id, &current->uid);
        }
        
        free(current);
        current = next;
    }
    manager->head = NULL;
    manager->activeCount = 0;
}

3.2 动态ID分配策略

3.2.1 查找最小可用ID

static uint8_t FindMinAvailableID(NodeManager* manager) {
    for (uint8_t id = MIN_VALID_ID; id <= MAX_VALID_ID; id++) {
        if (!IsIDUsed(manager, id)) return id;
    }
    return INVALID_ID;
}

该算法从MIN_VALID_ID开始遍历,返回第一个未被使用的ID。

3.2.2 ID使用检查

static bool IsIDUsed(NodeManager* manager, uint8_t id) {
    Node* current = manager->head;
    while (current) {
        if (current->id == id) return true;
        current = current->next;
    }
    return false;
}

3.3 心跳处理机制

uint8_t ProcessHeartbeat(NodeManager* manager, uint8_t nodeId, const DeviceUID* uid) {
    // 1. 检查是否已有相同UID的节点
    Node* existing = FindNodeByUID(manager, uid);
    if (existing) {
        existing->lastSeenMs = GetSysTimeMs(); // 更新活跃时间
        return existing->id;
    }

    // 2. 检查请求的ID是否已被占用
    if (nodeId != INVALID_ID && FindNodeByID(manager, nodeId)) {
        nodeId = INVALID_ID; // 如果已被占用,则重置为无效ID
    }

    // 3. 分配新ID
    if (nodeId == INVALID_ID) {
        nodeId = FindMinAvailableID(manager);
        if (nodeId == INVALID_ID) return INVALID_ID; // 无可用ID
    }

    // 4. 添加新节点
    return AddNode(manager, nodeId, uid) ? nodeId : INVALID_ID;
}
  • 心跳处理流程

    1. 如果是已知节点,更新其活跃时间

    2. 如果是新节点,检查请求ID是否可用

    3. 分配最小可用ID

    4. 添加新节点到管理器

3.4 超时检测机制

void CheckTimeoutNodes(NodeManager* manager) {
    uint64_t now = GetSysTimeMs();
    Node** pnode = &manager->head;

    while (*pnode) {
        Node* current = *pnode;
        if ((now - current->lastSeenMs) > HEARTBEAT_TIMEOUT) {
            *pnode = current->next; // 从链表中移除
            
            // 回调通知节点离线
            if (manager->onOffline) {
                manager->onOffline(current->id, &current->uid);
            }

            free(current); // 释放节点内存
            manager->activeCount--;
        } else {
            pnode = &(*pnode)->next;
        }
    }
}

该函数遍历所有节点,检查最后活跃时间是否超时,超时则移除节点并触发下线回调。

四、节点查找与管理

4.1 通过UID查找节点

static Node* FindNodeByUID(NodeManager* manager, const DeviceUID* uid) {
    Node* current = manager->head;
    while (current) {
        if (CompareDeviceUID(&current->uid, uid)) return current;
        current = current->next;
    }
    return NULL;
}

4.2 通过ID查找节点

static Node* FindNodeByID(NodeManager* manager, uint8_t id) {
    Node* current = manager->head;
    while (current) {
        if (current->id == id) return current;
        current = current->next;
    }
    return NULL;
}

4.3 获取活跃节点列表

uint8_t GetActiveNodeIDs(NodeManager* manager, uint8_t* outputBuffer, uint8_t bufferSize) {
    uint8_t count = 0;
    Node* current = manager->head;
    while (current && count < bufferSize) {
        outputBuffer[count++] = current->id;
        current = current->next;
    }
    qsort(outputBuffer, count, sizeof(uint8_t), CompareNodeIDs);
    return count;
}

五、回调机制实现

5.1 回调函数注册

void NodeManager_RegisterCallbacks(NodeManager* manager, 
                                 NodeOnlineCallback onOnline, 
                                 NodeOfflineCallback onOffline) {
    manager->onOnline = onOnline;
    manager->onOffline = onOffline;
}

5.2 示例回调函数

void OnNodeOnline(uint8_t id, const DeviceUID* uid) {
    printf("[Callback] Node %d is ONLINE!\n", id);
}

void OnNodeOffline(uint8_t id, const DeviceUID* uid) {
    printf("[Callback] Node %d is OFFLINE!\n", id);
}

六、应用示例

void TestNodeManager() {
    NodeManager manager;
    NodeManager_Init(&manager);
    
    // 注册回调
    NodeManager_RegisterCallbacks(&manager, OnNodeOnline, OnNodeOffline);

    // 模拟设备UID
    DeviceUID uid1 = {{0x00, 0x11, 0x22, 0x33, 0x44, 0x55}};
    DeviceUID uid2 = {{0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB}};
    
    // 节点上线
    ProcessHeartbeat(&manager, 1, &uid1);  // 指定ID=1
    ProcessHeartbeat(&manager, INVALID_ID, &uid2);  // 自动分配ID

    // 打印活跃节点
    PrintActiveNodes(&manager);

    // 模拟超时
    printf("\nSimulating timeout...\n");
    GetSysTimeMs();  // 模拟时间流逝
    CheckTimeoutNodes(&manager);
    PrintActiveNodes(&manager);

    // 主动释放节点
    printf("\nManually releasing node...\n");
    ReleaseNodeID(&manager, 2);
    PrintActiveNodes(&manager);

    // 清理
    NodeManager_Cleanup(&manager);
}

七、总结

本文详细介绍了一个高效的动态ID管理系统的设计与实现,该系统具有以下优点:

  • 灵活性:支持动态ID分配和释放

  • 可靠性:通过心跳机制确保节点状态准确

  • 可扩展性:易于添加新功能如安全验证等

  • 低开销:内存占用小,适合嵌入式环境

  • 事件驱动:通过回调机制实现松耦合

这种动态ID管理方案非常适合物联网设备、传感器网络等需要管理大量动态节点的嵌入式应用场景。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2339151.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

交易模式革新:Eagle Trader APP上线,助力自营交易考试效率提升

近年来&#xff0c;金融行业随着投资者需求的日益多样化&#xff0c;衍生出了众多不同的交易方式。例如&#xff0c;为了帮助新手小白建立交易基础&#xff0c;诞生了各类跟单社区&#xff1b;而与此同时&#xff0c;一种备受瞩目的交易方式 —— 自营交易模式&#xff0c;正吸…

健身会员管理系统(ssh+jsp+mysql8.x)含运行文档

健身会员管理系统(sshjspmysql8.x) 对健身房的健身器材、会员、教练、办卡、会员健身情况进行管理&#xff0c;可根据会员号或器材进行搜索&#xff0c;查看会员健身情况或器材使用情况。

捋一遍Leetcode【hot100】的二叉树专题

二叉树专题 除了后面两个&#xff0c;都挺简单 二叉树的中序遍历 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int …

【测试文档】项目测试文档,测试管理规程,测试计划,测试文档模版,软件测试报告书(Word)

原件获取列表&#xff1a; 系统测试方案-2.docx B-Web安全服务渗透测试模板.docx 压力测试报告.docx安全测试用例及解析.docx 测试计划.doc 测试需求规范.doc 测试需求指南.docx 测试用例设计白皮.doc 单元测试报告模板.doc 单元测试计划模板.doc 回归测试指南.doc 集成测试报…

Linux的联网网络管理攻略

RHEL9版本特点 在RHEL7版本中&#xff0c;同时支持network.service和NetworkManager.service&#xff08;简称NM&#xff09;。 在RHEL8上默认只能通过NM进行网络配置&#xff0c;包括动态ip和静态ip,若不开启NM&#xff0c;否则无法使用网络RHEL8依然支持network.service&am…

Linux上位机开发实践(SoC和MCU的差异)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 soc一般是指跑linux的芯片&#xff0c;而mcu默认是跑rtos的芯片&#xff0c;两者在基本原理方面其实差异不大。只不过&#xff0c;前者由于性能的原…

ios app的ipa文件提交最简单的方法

ipa文件是ios的app打包后生成的二级制文件&#xff0c;在上架app store connect或做testflight测试的时候&#xff0c;它提示我们需要使用xcode、transporter或xcode命令行等方式来上传。 而xcode、transporter或xcode命令行的安装都需要使用mac电脑&#xff0c;假如没有mac电…

详细解释浏览器是如何渲染页面的?

渲染流程概述 渲染的目标&#xff1a;将HTML文本转化为可以看到的像素点 当浏览器的网络线程收到 HTML 文档后&#xff0c;会产生一个渲染任务&#xff0c;并将其传递给渲染主线程的消息队列。在事件循环机制的作用下&#xff0c;渲染主线程取出消息队列中的渲染任务&#xff0…

Nacos安装及数据持久化

1.Nacos安装及数据持久化 1.1下载nacos 下载地址&#xff1a;https://nacos.io/download/nacos-server/ 不用安装&#xff0c;直接解压缩即可。 1.2配置文件增加jdk环境和修改单机启动standalone 找到bin目录下的startup.cmd文件&#xff0c;添加以下语句(jdk路径根据自己…

FPGA_YOLO(四)用HLS实现循环展开以及存储模块

Vivado HLS&#xff08;High-Level Synthesis&#xff0c;高层次综合&#xff09;是赛灵思&#xff08;Xilinx&#xff09;在其 Vivado 设计套件 中提供的一款工具&#xff0c;用于将 高级编程语言&#xff08;如 C、C、SystemC&#xff09; 直接转换为 硬件描述语言&#xff0…

ASP.NET MVC 实现增删改查(CRUD)操作的完整示例

提供一个完整的 ASP.NET MVC 实现增删改查&#xff08;CRUD&#xff09;操作的示例。该示例使用 SQL Server 数据库&#xff0c;以一个简单的 Product 实体为例。 步骤 1&#xff1a;创建 ASP.NET MVC 项目 首先&#xff0c;在 Visual Studio 中创建一个新的 ASP.NET MVC 项目…

MCP理解笔记及deepseek使用MCP案例介绍

文章目录 一、MCP介绍&#xff08;1&#xff09;使用MCP与之前的AI比较&#xff08;2&#xff09;原理&#xff08;3&#xff09;优点 二、deepseek使用MCP使用案例介绍 一、MCP介绍 全称 模型上下文协议 来源 由Claude母公司Anthropic于24年底开源发布 简介 AI大模型的标准化…

# 手写数字识别:使用PyTorch构建MNIST分类器

手写数字识别&#xff1a;使用PyTorch构建MNIST分类器 在这篇文章中&#xff0c;我将引导你通过使用PyTorch框架构建一个简单的神经网络模型&#xff0c;用于识别MNIST数据集中的手写数字。MNIST数据集是一个经典的机器学习数据集&#xff0c;包含了60,000张训练图像和10,000张…

LeetCode:DFS综合练习

简单 1863. 找出所有子集的异或总和再求和 一个数组的 异或总和 定义为数组中所有元素按位 XOR 的结果&#xff1b;如果数组为 空 &#xff0c;则异或总和为 0 。 例如&#xff0c;数组 [2,5,6] 的 异或总和 为 2 XOR 5 XOR 6 1 。 给你一个数组 nums &#xff0c;请你求出 n…

Perf学习

重要的能解决的问题是这些&#xff1a; perf_events is an event-oriented observability tool, which can help you solve advanced performance and troubleshooting functions. Questions that can be answered include: Why is the kernel on-CPU so much? What code-pa…

齐次坐标变换+Unity矩阵变换

矩阵变换 变换&#xff08;transform)&#xff1a;指的是我们把一些数据&#xff0c;如点&#xff0c;方向向量甚至是颜色&#xff0c;通过某种方式&#xff08;矩阵运算&#xff09;&#xff0c;进行转换的过程。 变换类型 线性变换&#xff1a;保留矢量加和标量乘的计算 f(x)…

Pandas取代Excel?

有人在知乎上提问&#xff1a;为什么大公司不用pandas取代excel&#xff1f; 而且列出了几个理由&#xff1a;Pandas功能比Excel强大&#xff0c;运行速度更快&#xff0c;Excel除了简单和可视化界面外&#xff0c;没有其他更多的优势。 有个可怕的现实是&#xff0c;对比Exce…

启动vite项目报Unexpected “\x88“ in JSON

启动vite项目报Unexpected “\x88” in JSON 通常是文件被防火墙加密需要寻找运维解决 重启重装npm install

HTTP测试智能化升级:动态变量管理实战与效能跃迁

在Web应用、API接口测试等领域&#xff0c;测试场景的动态性和复杂性对测试数据的灵活管理提出了极高要求。传统的静态测试数据难以满足多用户并发、参数化请求及响应内容验证等需求。例如&#xff0c;在电商系统性能测试中&#xff0c;若无法动态生成用户ID、订单号或实时提取…

关于一对多关系(即E-R图中1:n)中的界面展示优化和数据库设计

前言 一对多&#xff0c;是常见的数据库关系。在界面设计时&#xff0c;有时为了方便&#xff0c;就展示成逗号分割的字符串。例如&#xff1a;学生和爱好的界面。 存储 如果是简单存储&#xff0c;建立数据库&#xff1a;爱好&#xff0c;课程&#xff0c;存在一张表中。 但…