文章目录

  • 概述
  • WIFI8266 通信模组
    • WIFI模组也用AT指令?
    • ESP8266 内置协议栈?
    • 支持的无线网络模式
    • MCU通过串口与模组交互
  • Wifi模组做客户端
    • PC-AT接入路由器
    • 向本地TCP服务发数据
    • 用代码接入你家路由器
    • 已接入AP(你家Wifi)
  • 平台侧开发
  • 工程配置和编译
    • 工程配置
    • 编译不过
    • WIFI连接参数
    • 接入AP成功,IoTDA失败
    • 无可用加密套件
  • 成功接入平台

概述

本实验基于WIFI模组实现智慧农业案例,实现实时数据采集,实现命令下发和响应,实现端云互通。实验目的包括:

  • 掌握Wifi通信方式的配置。
  • 掌握智慧农业案例的开发过程。
  • 掌握Wifi+DTLS+PSK接入华为云物联网平台的方法。
  • 了解LiteOS以及DTLS的裁剪,避免板卡Flash不足以存储编译结果。
  • NB-IoT模组通过串口与主板MCU以AT指令交互,wifi模组也是。

@NOTE
转载请标明出处,https://blog.csdn.net/quguanxin/category_12929470.html

@HISTORY
从本实验开始,我将放弃使用LiteOS Stduio集成开发环境,转而使用新构建的 GitBash+GCC+CortexDebug 集成开发环境。在原本的计划里头,本文是要探寻LwM2M/CoAP与AT指令、Wifi、NB-IoT之间的关联,但实际上并没有,因为我遇到了其他困难。我原本以为在智慧农业NB-IoT实验基础上,Wifi实验过程会很顺利,但事与愿违。在编译阶段,启用DTLS模块后,遇到了程序大小超过Flash总额的问题。在平台接入阶段,由于错把设备ID当做设备标识码使用,导致接入平台失败。为了分析和解决上述问题,延伸多写了其他几篇文章。

WIFI8266 通信模组

WIFI8266通信模块是小熊派开发板用于通过Wi-Fi传输数据的通信扩展板,板载乐鑫 ESP8266 Wi-Fi通信模组。
在这里插入图片描述

WIFI模组也用AT指令?

从学习华为云物联网开始,这可能是我给自己挖的最大的坑,我一直以为AT指令是NB-IoT通信下的一种特有的指令,可现在来看,WIFI通信模组也是要使用AT指令的。那么,我们不得不重新来审视什么是AT指令?

AT指令绝非仅限于NB-IoT,而是贯穿各类通信模组(WiFi、4G蓝牙等)的通用控制协议,堪称物联网设备的 “神经系统语言”。
AT是"Attention"的缩写,历史遗留术语,它起源于很久以前,NB-IoT只是其后来的一个受益者而已。它在1981年由Hayes公司设计,用于调制解调器拨号控制(如ATDT拨号),通过文本化命令实现对通信模块的操控,隔离底层硬件差异,使主控MCU无需理解复杂射频协议。其本质是通过ASCII字符串控制通信模组的协议,实现设备与模组间的交互。

3GPP TS 27.007,定义基础指令如 AT+CSQ(信号强度),不是只指针对NB的,而是覆盖蜂窝网络,也包含4G/5G 等。但是 Wi-Fi 不在3GPP规范范围内,其AT指令由各芯片厂商(如乐鑫ESP8266)自行定义。虽无全球统一标准,但厂商也常会参考3GPP语法,采用类似格式,如,AT+CWJAP(连接Wi-Fi)、AT+CWSAP(创建热点)等指令。只是格式差不多,指令名不一样,
在这里插入图片描述
小熊派社区,扩展板资料中也有 <ESP-12F(ESP8266) AT指令使用示例.pdf> 等可以下载参考。在小熊派开发板这个场景下,AT指令是主板(MCU)与通信模组之间的控制语言,用于操控模组底层行为。

ESP8266 内置协议栈?

ESP8266 模块是有独立运行能力的哈,这点一定要提前意识到。
其内部集成Tensilica L106 32位微控制器,自带Flash存储,可直接运行固件。该固件包含完整的 LwIP 协议栈,支持 IPv4 的TCP、UDP、HTTP 等常见协议。ESP8266 扩展板仅通过 UART/TX/RX引脚 与主板通信,主板仅需实现串口数据传输,不参与任何协议处理。主板(如STM32)仅需通过UART串口发送AT指令控制ESP8266,例如,AT+CIPSTART=“TCP”,“192.168.1.100”,8080 建立TCP连接。
进一步的,这意味着什么呢?我们不需要在主板程序中启用LWIP协议栈,这将会减少很多的一笔开销。
需要注意的是,ESP8266模组并不内置LwM2M客户端,
如前文所述,其内置LwIP TCP/IP协议栈,支持基础网络通信,但并无内置LwM2M/CoAP这种更上层的应用层协议。在理论上,Wifi模组可以通过OpenCPU/SDK可集成CoAP/LwM2M,但需开发者手动实现,且资源占用较高。

支持的无线网络模式

ESP8266 Wi-Fi扩展板(如小熊派开发板所用)支持三种主要无线网络模式:
Station(STA)模式SoftAP(AP)模式STA+AP混合模式。这些模式决定了模块如何与其他设备或网络交互,适用于不同物联网场景。
在这里插入图片描述
Station (STA) 模式 - 客户端角色,
源自 IEEE 802.11(Wi-Fi)标准术语,指连接到无线网络的终端设备,如手机、笔记本电脑。你的手机连接家里路由器时,手机(相关通信模组)就是 Station,哈哈,这里的Station其含义车站的乘客,不是车站,AP才是车站,互联网算是动车高铁吧。当扩展板处于此工作模式时,它就相当于你的手机一样,去链接你家的路由器。该角色下的设备,会包含扫描可用网络、发起认证连接(向AP接入点的认证请求)、获取IP地址(DHCP客户端)等技术行为。

Access Point (AP) 模式 - 服务端角色,
IEEE 802.11 标准定义的无线网络接入点,即提供Wi-Fi信号的设备,如,路由器。也就是说扩展板可以像我们家路由器那样,做为网络的创建者和服务提供者,主动广播SSID创建无线网络、为STA设备分配IP、路由数据,组件本地局域网。该角色下的设备,会有,广播信标帧、宣告网络存在,认证连接请求(如WPA2-PSK握手),作为DHCP服务器分配IP地址,等技术行为。SoftAP 区别于硬件AP(专用路由器芯片),其通常是资源受限的,具有临时性,通常用于特定场景(如配网),在早期家用无线摄像头配置方案里确实见过。

MCU通过串口与模组交互

在<IoT/透过oc_lwm2m和at源码,分析NB-IoT通信模组和主板MCU之间的通信过程和工作机制> 文中,我们已经从软件源码层级上,分析论证了NB-IoT模组与主板MCU之间是通过串口进行通信的。那么ESP8266同样依赖UART传输AT指令和数据吗?首先,答案是肯定的。但在本文我们先不急着从软件实现层次上去分析这个事情。因为看看硬件原理图,一切就不容狡辩。实锤。

Wifi/ESP8266通信模组原理图,
在这里插入图片描述
NB-IoT通信模组原理图,
在这里插入图片描述
如上,无论是WiFi或NB-IoT通信模组,都具有串口Rx/Tx通信管脚导出,用于和主板进行串口通信,交互AT指令和数据。

Wifi模组做客户端

在我们的实验5-Wifi智慧农业,中 ESP8266,其工作在客户端模式。

PC-AT接入路由器

其实一开始,我不知道ESP8266这东西还能用PC-AT指令接入接力的路由器,我是在看了一会源码后才发现的。 <ESP-12F(ESP8266) AT指令使用示例.pdf> 等手册可以从文中连接下载。接下来,我们根据手册内容,进行些简单实验。与NB-IoT-AT指令的PC实践一样,拨码开发要拨到PC侧,但是这里的波特率是115200,不与PC-AT一样了哈。

//设置模组为客户端模式
AT+CWMODE=3
//固件中是纯字符串解析,相当脆弱,一定要注意不要在任何地方不要乱加空格
AT+CWJAP="HUAWEI-IoT","1xxxxxxxxx2+"

在这里插入图片描述
建立TCP连接,
在这里插入图片描述
这里还闹腾了乌龙。早期我使用Wifi代码连接到平台的实践中,我连接的是家里凌霄路由器的客人WIFI,当时我是实验成功的。现如今用PC-AT指令实验,依据ESP8266的AT指令手册,使用网络助手在本地创建TCP服务端,使用AT指令控制ESP8266建立TCP连接,结果总是连接不上。我关闭了防火墙、禁用了所有其他网络适配器,依然不行。但是当我切换到正常的WIFI网络时,我就可以ping通了。当然,关闭防火墙或进行更细粒度的策略配置,肯定是必要,否则你肯定是ping不通的。至于为啥客网在PC-AT指令实现时,存在不通,可能这是凌霄Q6独有策略吧,我没再深究,没有那个时间。

向本地TCP服务发数据

//查询模组的IP地址
AT+CIFSR
//测试从模组到PC主机的可达性
AT+PING="192.168.155.10"
//连接到本地TCP服务
AT+CIPSTART="TCP","192.168.3.7",62100
//数据发送/发多了会被截断哈
AT+CIPSEND=4

如下图,我们发送 CSDN_DAHE_QU 多个字符,最终实际发送4个字符成功.
在这里插入图片描述
我们前文提到过,ESP8266也是用AT指令与MCU通信的,看到上述CIPSTART、CIPSEND等指令,去源码里搜一下就豁然开朗了。

用代码接入你家路由器

首先在.config配置中,修改CONFIG_ESP8266_SSID和CONFIG_ESP8266_PWD的值,为你家的Wifi名称和密码。这两个宏定义会在 ESP8266 驱动程序中使用,并最终作为 esp8266_joinap 函数的输入参数,具体过程如下,

//宏重命名
#define WIFI_SSID                 CONFIG_ESP8266_SSID  //在.config模式下定义
#define WIFI_PASSWD               CONFIG_ESP8266_PWD   //在.config模式下定义
//使用上述宏作实参的函数实现
static bool_t esp8266_joinap(char *ssid, char *passwd) {char cmd[64];(void) memset(cmd,0,64);(void) snprintf(cmd,64,"AT+CWJAP_CUR=\"%s\",\"%s\"\r\n",ssid, passwd);return esp8266_atcmd(cmd,"OK");
}

通过上述函数实现可以看出来,底层通过调用扩展板的AT指令,完成扩展板与AP的链接过程。这里AT指令,可参见相关手册。在代码调试前,可以先基于PC上的AT指令测试上述连接过程。

已接入AP(你家Wifi)

这个过程挺顺利的。我在终端中配置的是Q6访客网的连接信息,在Q6的Web管理页面中,可以检索到扩展板连接情况。
在这里插入图片描述

平台侧开发

与实验-5/基于NB-IoT,使用相同产品模型和设备定义也是可以的。我们这里只重点再强调下设备注册中的设备秘钥配置问题。为了更好的说明一些问题,我们重新注册一个新设备,包括密码设置什么的,截图上都不打码,以更好的理解。
在这里插入图片描述
密码设置时,我坑了自己好几次了,哈哈,还每次都觉得自己理解无误。
在这里插入图片描述
上述红色告警信息有些不靠谱,自己与左侧提示信息就矛盾着。
首先,华为云IoT平台在创建注册设备时,似乎无法区分是否为NB设备。其次,你输入非16进制(0~F)字符,如H、J、Q等字符时,是无法通过输入检查的。上图右侧的告警,也很绕人。所谓1个十六进制字符,并不是字符串单字符的概念,如上0x00、0x99、0xAA 都只算是一个字符,即单字节8bit的16进制数据。是字节数据,不是字符数据,以A5为例,它可以使用0xA5这个单字节存储或传输,当然也可以使用0x41(‘A’)和0x35(‘5’)两个字节来存储或传输。

另外,已经验证过的一个问题是,
使用Wifi模组进行通信时,我们可以任意但唯一的指定设备标识码,不必一定是MAC。NB-IoT设备不行哦,只能是IMEI。

工程配置和编译

工程配置,并不复杂,基本可按照HCIP-IOT实验手册进行。编译过程中倒是遇到了不少的麻烦。

工程配置

修改.config中的串口波特率。将NB-IoT连接模式修改为WIFI模式,详情可参见具体源码,点击此链接下载即可。

CONFIG_UARTAT_BAUDRATE=115200
CONFIG_TCPIP_AL_ENABLE=y
CONFIG_ESP8266_ENABLE=y
CONFIG_ESP8266_SSID="HUAWEI-IoT"
CONFIG_ESP8266_PWD="135836xxx02+"
CONFIG_DTLS_AL_ENABLE=y    //记得打开
CONFIG_MBEDTLS_ENABLE=y    //记得打开
CONFIG_MBEDTLS_PSK=y       //记得打开
CONFIG_OCLWM2M_ENABLE=y
CONFIG_OCLWM2MTINY_ENABLE=y

编译不过

开启上述DTLS三联配置后,编译报错,说是Flash溢出了,即Flash存不下编译生成的elf可执行文件了,
在这里插入图片描述
小熊派开发板使用的STM32L431RCT6,其片内Flash只有256K,确实不大。通过芯片手册,或小熊派官网可以查询到,
在这里插入图片描述
为了验证编译器报错是否靠谱,我们先造个假,欺骗下编译器。我们修改在 LiteOS_Lab_HCIP\targets\STM32L431_BearPi\GCC 目录下的 os.ld 配置文件,临时设置Flash为512K,重新编译。
在这里插入图片描述
被欺骗的编译器是可以通过编译的。左侧是启用DTLS前的编译结果,
在这里插入图片描述
启用DTLS后,作为编译结果的程序大出来68000字节,约合65KB字节,为什么DTLS这么耗费存储呢?是源码中开启的模块宏,如一些调试和日志模块。包括底层LiteOS的一些暂时不用的模块,都开启了。需要裁减,但是这很费心神,愁得慌啊真是。我当时先的办法,
0、裁简DTLS模块。(LiteOS我还不是特别熟,可能裁减不好,DTLS我试了试,各个细枝末节有关联,也没有参考)
1、不使用DTLS,退回到不安全模式。 (后记/应该确实不支持了)
2、是使用外扩展的Flash,来存放程序。(这不简单啊)
3、放弃使用小熊派开发板,转而使用Flash更大的芯片或板子。(太贵了)

哎,每个都不简单啊。好在天无绝人之路,LiteOS中的Wifi示例程序,尽然裁减的不错,可以满足编译呢。使用小熊派提供的示例程序,
…\bearpi-iot_std_liteos-master\targets\STM32L431_BearPi\Demos\oc_wifi_lwm2m_agriculture,结合自己的代码,结果如下,
在这里插入图片描述

WIFI连接参数

基于LiteOS lwM2M_al 的核心封装实现,在应用层看来,NB-IoT通信或基于Wifi通信是一致的,连设备接入流程的代码都是一致的,只是在接入参数配置上有所区别,这是真替用户考虑啊。应用层代码实现请参考 #<IoT/HCIP实验-5/基于NB-IoT的智慧农业实验(平台侧开发+端侧编码+基础调试分析)>#,本文只简单说说WIFI通信下的设备接入配置。

#define cn_app_pskid     "csdn_dahe_0528"
//#define cn_app_psk     "00112233445566778899" //这是错误的哈
const unsigned char  cn_app_psk[]={0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA};
#define cn_app_psklen     10 //建议使用sizeof(cn_app_psk)static int app_report_task_entry() {...oc_param.app_server.address = CONFIG_APP_SERVERIP;oc_param.app_server.port = CONFIG_APP_SERVERPORT;oc_param.app_server.ep_id = CONFIG_APP_ENDPOIINT_ID;oc_param.boot_mode = en_oc_boot_strap_mode_factory;oc_param.rcv_func = app_msg_deal;#if 1 //CoAPS/DTLS加密oc_param.app_server.ep_id = cn_app_pskid;oc_param.app_server.psk = (char *)cn_app_psk;oc_param.app_server.psk_len = sizeof(cn_app_psk);oc_param.app_server.psk_id = cn_app_pskid;#endifret = oc_lwm2m_config( &oc_param);...
}

特别注意,特别注意,WIFI下的oc_param.app_server.psk,即cn_app_psk定义,与NB-IoT不同,不是使用字符串哈。

接入AP成功,IoTDA失败

异常分析,小熊派开发板使用Wifi通信扩展板,接入AP成功,但是连接平台失败,

[DEBUG][189183][registration_step:1382] [189][registration_step:1382] targetP Status: STATE_REG_PENDING
[DEBUG][189192][transaction_step:505] [189][transaction_step:505] Entering
[DEBUG][189199][lwm2m_step:767] [189][lwm2m_step:767] Final timeoutP: ld
[DEBUG][189206][lwm2m_step:769] [189][lwm2m_step:769] Final state: STATE_REGISTERING

小熊派开发板WiFi接入AP成功后连接华为云平台失败(状态卡在STATE_REG_PENDING和STATE_REGISTERING)。平台地址或端口配置已经在NB-IoT实验中进行过实验(后来发现这是病灶)。因此分析最可能导致上述问题的原因是,DTLS握手失败。

无可用加密套件

握手失败错误-0x6900通常因未启用CCM_C或PSK导致。
在这里插入图片描述
在这里插入图片描述
我在尝试自己裁减HCIP-IoT-Lab代码中的DTLS算法库时,曾经遇到以上问题,关键原因是无可用加密套件,或者是PSK与平台设置不一致,在后续的其他文章中,我们还会单独针对DTLS采集重新讨论。

成功接入平台

设备侧接入日志,
在这里插入图片描述
平台侧设备详情,
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

定时器输出PWM波配置(呼吸灯)

使用定时器 4 通道 3 生成 PWM 波控制 LED1 &#xff0c;实现呼吸灯效果。 频率&#xff1a;2kHz&#xff0c;PSC71&#xff0c;ARR499pwm.c:#include "pwm.h" // 本模块头文件&#xff1a;应声明 pwm_init/pwm_compare_set 等原型、并包含 HAL 头//&#xff08;示…

[ai-agent]环境简介之沙盒e2b vs daytona

所谓的环境的就是agent运行在哪里&#xff0c;或者是agent和那里进行交互。 最常见的环境就是本地开发环境&#xff0c;也就是个人主机&#xff0c;但是存在问题就是没有办法出网和横向扩展。 在沙盒之前也是有其他选择的&#xff1a; 云服务器&#xff0c; 虚拟机&#xff0c;…

【前端面试题】前端面试知识点(第三十一题到第六十一题)

三十一. CSS实现垂直水平居中 实现元素的垂直水平居中是前端开发中的常见需求,主要有以下几种思路: text-align + line-height实现单行文本水平垂直居中 适用于单行文本元素,通过text-align: center实现水平居中,line-height等于容器高度实现垂直居中 text-align + vertic…

嵌入式练习项目——————抓包获取天气信息

一、内容 尝试通过实时天气接口 - 数据接口 - NowAPI此网站获取天气信息&#xff0c;实现可以发送城市查询当前天气和未来天气 二、获取请求报文 可以根据测试示例看到获取内容&#xff0c;此时数据是cJSON格式&#xff0c;我们首先要通过合适的网址抓包获取到请求报文&#x…

Python爬虫实战:研究NewsCrawl ,构建新浪和网易新闻数据采集系统

1. 引言 1.1 研究背景与意义 在信息时代,新闻作为社会动态、公众观点的重要载体,其传播速度与影响力持续扩大。传统的人工筛选与采集方式已无法满足对海量新闻数据的高效处理需求,亟需自动化工具实现大规模、结构化的新闻数据采集。网络爬虫技术作为一种按照预设规则自动抓…

PyTorch神经网络工具箱全解析:nn.Module vs nn.functional

&#x1f50d; 为何需要神经网络工具箱&#xff1f; 在仅用 Autograd 和 Tensor 实现模型时&#xff0c;开发者需手动设置参数梯度&#xff08;requires_gradTrue&#xff09;、反向传播&#xff08;backward()&#xff09;及梯度提取&#xff0c;过程繁琐且易出错。nn 工具箱应…

Java注解学习记录

目录 一、为什么要学注解&#xff1f; 二、注解是什么&#xff1f; 三、为什么要使用注解&#xff1f; 四、注解的作用 五、注解的分类 5.1 元注解 Retention&#xff08;/ rɪˈtenʃ(ə)n /&#xff09; ★★★★★ Target ★★★★★ Inherited(/ ɪnˈherɪtɪd /…

43.安卓逆向2-补环境-使用unidbg(使用Smali语法调用方法和使用方法地址调用方法)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a;图灵Python学院 工具下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1bb8NhJc9eTuLzQr39lF55Q?pwdzy89 提取码&#xff1…

【Kubernetes知识点问答题】Pod 调度

1. 如何将特定 Pod 调度到指定的节点&#xff1f;可以使用下列方法中的任何一种来选择 K8s 对特定 Pod 的调度&#xff1a;① 与节点标签匹配的 nodeSelector&#xff1a;在 Pod 的规范中使用 nodeSelector 字段来指定节点标签&#xff0c;以便将 Pod 调度到具有特定标签的节点…

wordpress显示时间日期的几种常见的方式

在WordPress中&#xff0c;显示时间日期有多种常见方式&#xff0c;包括使用默认设置、模板标签、插件等&#xff0c;以下是详细介绍&#xff1a; 使用默认设置 WordPress的默认设置允许你在文章列表中显示文章的发布时间。登录到WordPress后台&#xff0c;在“设置”中找到“…

基于飞算JavaAI实现布隆过滤器防止缓存穿透:原理、实践与全流程解析

引言&#xff1a;当缓存失效时&#xff0c;系统如何避免“雪崩式崩溃”&#xff1f; 在互联网高并发场景中&#xff08;如电商秒杀、社交平台热点新闻&#xff09;&#xff0c;缓存是提升系统性能的核心手段——将频繁访问的数据&#xff08;如商品详情、用户信息&#xff09;存…

DeepResearch开源与闭源方案对比

在这个AI不再只是聊天工具的时代&#xff0c;"深度研究"已经成为大语言模型&#xff08;LLM&#xff09;的一项新能力。先进的LLM不再只是给出快速的一次性回答&#xff0c;而是可以像研究助手一样工作——搜索网上信息&#xff0c;调用各种工具&#xff08;比如搜索…

UniApp 页面传参方式详解

在 UniApp 开发中&#xff0c;页面间参数传递是核心功能之一。以下是 8 种常用的传参方式&#xff0c;每种方式都有其适用场景和特点&#xff1a;一、URL 拼接传参&#xff08;最常用&#xff09; 适用场景&#xff1a;简单数据传递&#xff0c;如 ID、状态值等基础类型数据 实…

音频分类标注工具

pyqt 分类标注工具&#xff1a;import glob import sys import json import os from PyQt5.QtWidgets import (QApplication, QMainWindow, QTableWidget, QTableWidgetItem,QSplitter, QVBoxLayout, QWidget, QPushButton, QRadioButton,QButtonGroup, QLabel, QHBoxLayout, Q…

云计算-Kubernetes+Istio 实现金丝雀发布:流量管理、熔断、流量镜像、ingreess、污点及pv案例实战

介绍 在微服务架构中,如何安全、高效地实现服务发布与流量管理是保障业务稳定性的核心挑战。金丝雀发布(Canary Release)、灰度发布等策略通过精细化的流量控制,可有效降低新版本上线风险, Istio 作为主流的服务网格(Service Mesh)工具。 此次Istio 在 Kubernetes 集群…

12.web api 3

定时器-间歇函数

ComfyUI进阶:EchoMimic插件全解析,让静态肖像实现音频驱动的精准口型动画

在数字内容创作中&#xff0c;让静态肖像“开口说话”并做出自然表情&#xff0c;是提升交互感与沉浸感的关键。传统动画制作需专业人员逐帧调整口型与表情&#xff0c;成本高且效率低。ComfyUI的EchoMimic插件通过音频驱动技术&#xff0c;实现了“输入音频→自动生成匹配口型…

链式前向星、vector存图

场景设定 想象你是一个社交达人&#xff0c;要记录你和所有朋友的关系&#xff08;这就是“图”&#xff09;。每个朋友是一个节点&#xff0c;关系是一条边。你需要快速回答&#xff1a;“我有哪些朋友&#xff1f;”&#xff08;遍历邻居&#xff09;。方式1&#xff1a;链式…

YAML 中定义 List 的几种方式

在 YAML 配置文件中定义 List 并在 Spring 应用中注入是非常常见的操作&#xff0c;下面详细介绍具体写法和注入方式。一、YAML 中定义 List 的几种方式1. 缩进式写法&#xff08;推荐&#xff09;最常用的方式&#xff0c;通过短横线 - 加空格表示列表项&#xff1a;yaml# app…

C# 反射和特性(自定义特性)

自定义特性 你或许已经注意到了&#xff0c;应用特性的语法和之前见过的其他语法有很大不同。你可能会觉得特 性是一种完全不同的结构类型&#xff0c;其实不是&#xff0c;特性只是一种特殊的类。 有关特性类的一些要点如下。 用户自定义的特性类叫作自定义特性。所有特性类都…