LLDP(链路层发现协议)详解及C/C++代码实现

news2024/12/28 8:23:43

LLDP(链路层发现协议)是一种IEEE标准协议(IEEE 802.1AB),它定义了封装在以太网帧中的消息,目的是通过默认情况下每30秒从每个端口定期重传一次,为设备提供一种向LAN(局域网)上的其他设备宣布基本设备信息的方式。它是一个类似于CDP(思科发现协议)的标准化协议。它是一个独立于供应商的链路层协议,用于网络拓扑、故障排除和网络管理自动化。

LLDP的好处

LLDP具有以下优点:

1.简化了网络管理工具在多供应商环境中的使用。
2.准确发现物理网络拓扑,简化企业网络中的故障排除。
3.支持在多供应商环境中发现工作站。
4.提供设备功能,并支持可选的系统名称和描述以及管理地址。
5.提供可用于检测双工和速度不匹配的信息。
6.发现IP地址配置错误或无法访问的设备。

LLDP的缺点:

1.LLDP运行成本高于CDP。
2.对某些设备的有限支持:虽然LLDP是一个开放的标准协议,但某些设备可能不完全支持它,或者支持有限。例如,在某些虚拟交换机(如VMware)上,设备发现仅支持CDP。
3.实现成本更高:与CDP等其他协议相比,LLDP的实现可能需要更多的资源和配置,这可能会导致更高的实现成本。
4.安全风险:LLDP可能会暴露有关网络设备的敏感信息,攻击者可能会利用这些信息。例如,攻击者可以使用LLDP来识别网络拓扑、设备类型和软件版本,以计划攻击或收集有关网络的情报。
5.有限的向后兼容性:LLDP可能与不支持该协议的旧设备或遗留系统不向后兼容。这可能会限制其在新旧设备混合的环境中的使用。
6.功能有限:LLDP仅提供有关网络设备的基本信息,如设备类型、软件版本和端口信息。对于一些需要更高级功能(例如服务质量(QoS)或网络策略实施)的应用程序来说,这可能是不够的。
7.互操作性问题:尽管LLDP是一个开放的标准协议,但不同的供应商可能会以不同的方式实现它,这可能会导致互操作性的问题。这可能使得在来自不同供应商的设备之间交换信息或将LLDP与其他网络管理系统集成变得困难。

Frame format

在这里插入图片描述

在LLDP中,每个设备以以太网帧的形式以固定的间隔从其每个接口发送信息。每个帧包含一个LLDP数据单元(LLDPDU)。每个LLDPDU都是一个类型长度值(TLV)结构序列。EtherType字段设置为0x88cc。每个LLDP帧都以机箱ID、端口ID和TTL(生存时间)或跃点限制开始。该帧以一个名为LLDPDU结束的特殊TLV结束,其中类型和长度字段均为0。LLDP规范允许组织定义和编码自己的TLV。这些被称为组织特定TLV,它们以LLDP TLV类型值127开始。

LLDPDU types
LLDPDU有两种类型:普通LLDPDU和停机咨询LLDPU。普通LLDPDU将关于本地设备的管理信息提供给该设备的邻居。这是传输强制性和可选TLV的一个。同时,当端口被禁用、LLDP被禁用或交换机被重新启动时,LLDP关闭帧被传输到相邻单元,用信号表示LLDP信息不再有效。

LLDP消息的结构

LLDP通过称为LLDPDU的特定数据单元交换信息。这些数据单元由TLV组成,并且每个TLV字段对应于特定类型和长度。LLDP标准IEEE 802.1AB有三个TLV,它们在LLDP的开头是强制性的,顺序如下:

  • 类型1=机箱ID(标识设备)

  • 类型2=端口ID(标识端口)

  • 类型3=生存时间(告诉接收设备接收的信息应保持有效的时间)

  • 类型4=端口描述(显示有关端口的详细信息)

  • 类型5=系统名称(显示设备的给定名称)

  • 类型6=系统说明(显示软件版本)

  • 类型7=系统功能(告诉设备的主要功能和功能)

  • 类型8=管理地址(显示设备的IP或MAC地址)

在LLDPDU的末尾,以下TLV是强制性的:


类型0=LLDPDU结束(表示数据单元结束)

IEEE 802.1 Subtypes

static const value_string ieee_802_1_subtypes[] = {
	{ 0x01,	"Port VLAN ID" },			/* 802.1Q - D.2.1 */
	{ 0x02, "Port and Protocol VLAN ID" },		/* 802.1Q - D.2.2 */
	{ 0x03, "VLAN Name" },				/* 802.1Q - D.2.3 */
	{ 0x04, "Protocol Identity" },			/* 802.1Q - D.2.4 */
	{ 0x05, "VID Usage Digest" },			/* 802.1Q - D.2.5 */
	{ 0x06, "Management VID" },			/* 802.1Q - D.2.6 */
	{ 0x07,	"Link Aggregation" },			/* 802.1Q - D.2.7 */
	{ 0x08,	"Congestion Notification" },		/* 802.1Q - D.2.8 */
	{ 0x09, "ETS Configuration" },			/* 802.1Q - D.2.9 */
	{ 0x0A, "ETS Recommendation" },			/* 802.1Q - D.2.10 */
	{ 0x0B, "Priority Flow Control Configuration" },/* 802.1Q - D.2.11 */
	{ 0x0C, "Application Protocol" },		/* 802.1Q - D.2.12 */
	{ 0x0D, "EVB" },				/* 802.1Q - D.2.13 */
	{ 0x0E, "CDCP" },				/* 802.1Q - D.2.14 */
	{ 0x0F, "Port extension" },			/* 802.1BR - B.2 */
	{ 0x10, "Application VLAN" },			/* 802.1Q - D.2.15 */
	{ 0x11, "LRP ECP Discovery" },			/* 802.1CS - C.2.1 */
	{ 0x12, "LRP TCP Discovery" },			/* 802.1CS - C.2.2 */
	{ 0x13, "Congestion Isolation" },		/* 802.1Qcz - D.2.15 */
	{ 0x14, "Topology Recognition" },		/* 802.1Qcz - D.2.16 */
	{ 0, NULL }
};

组织特定TLV

LLDP规范允许各种组织定义和编码他们自己的TLV。这些被称为组织特定TLV。所有特定于组织的TLV都以LLDP TLV类型值127开头。

Organizationally Specific TLV (Type = 127)

组织特定TLV的长度字段后面跟着3个八位位组(24位)的组织唯一标识符(OUI)值,该值后面跟着1个八位位位组的组织定义的子类型。

IEEE 802.3 Subtypes

static const value_string ieee_802_3_subtypes[] = {
	{ 0x01,	"MAC/PHY Configuration/Status" },
	{ 0x02,	"Power Via MDI" },
	{ 0x03,	"Link Aggregation" },
	{ 0x04,	"Maximum Frame Size" },
	{ 0x05,	"EEE (Energy-Efficient Ethernet)" },
	{ 0x07,	"IEEE 802.3br Additional Ethernet capabilities" },
	{ 0, NULL }
};

Media 相关信息

LLDP-MED是LLDP的扩展。该协议专门用于支持IP语音(VOIP)应用。LLDP-MED能够在网络连接设备和媒体端点(如软电话、IP电话、VOIP网关和会议桥)之间进行网络发现。默认情况下,网络设备只发送LLDP数据包,直到它从端点设备接收到LLDP-MED数据包。然后,它将继续发送LLDP-MED数据包,直到它所连接的远程设备停止具有LLDP-MED能力为止。

/* Media Subtypes */
static const value_string media_subtypes[] = {
	{ 1,	"Media Capabilities" },
	{ 2,	"Network Policy" },
	{ 3,	"Location Identification" },
	{ 4,	"Extended Power-via-MDI" },
	{ 5,	"Inventory - Hardware Revision" },
	{ 6,	"Inventory - Firmware Revision" },
	{ 7,	"Inventory - Software Revision" },
	{ 8,	"Inventory - Serial Number" },
	{ 9,	"Inventory - Manufacturer Name" },
	{ 10,	"Inventory - Model Name" },
	{ 11,	"Inventory - Asset ID" },
	{ 0, NULL }
};

/* Media Class Values */
static const value_string media_class_values[] = {
	{ 0,	"Type Not Defined" },
	{ 1,	"Endpoint Class I" },
	{ 2,	"Endpoint Class II" },
	{ 3,	"Endpoint Class III" },
	{ 4,	"Network Connectivity" },
	{ 0, NULL }
};

/* Media Application Types */
static const value_string media_application_type[] = {
	{ 0,	"Reserved" },
	{ 1,	"Voice" },
	{ 2,	"Voice Signaling" },
	{ 3,	"Guest Voice" },
	{ 4,	"Guest Voice Signaling" },
	{ 5,	"Softphone Voice" },
	{ 6,	"Video Conferencing" },
	{ 7,	"Streaming Video" },
	{ 8,	"Video Signaling" },
	{ 0, NULL }
};

LLDP操作模式

LLDP代理以以下三种模式中的任何一种模式操作:

仅传输模式:代理只能传输有关本地系统的功能和当前状态的信息。

仅接收模式:代理只能接收有关远程系统的功能和当前状态的信息。

传输和接收模式:代理可以传输本地系统的能力和状态信息,也可以接收远程系统的能力与状态信息。

无论何时传输倒计时计数器到期,或者如果LLDP信息已经改变,LLDP代理都会向启用LLDP的相邻设备发送LLDP帧。LLDP管理器获取MIB(管理信息库)内部的信息,并将其格式化为TLV并插入LLDPDU。当代理接收到此LLDPDU时,它会进行检查以确保它包含正确的强制TLV序列,然后验证可选TLV。如果出现错误,它将被删除。而有效的TLV存储在邻居数据库中。

LLDP(链路层发现协议)详解及C/C++代码实现

/* TLV globals */

#define TLV_LLDPDU_END 0x00
#define TLV_CHASSIS_ID 0x01
#define TLV_PORT_ID 0x02
#define TLV_TTL 0x03
#define TLV_PORT_DESC 0x04
#define TLV_SYSNAME 0x05
#define TLV_SYS_DESC 0x06
#define TLV_SYS_CAP 0x07
#define TLV_MGMT_ADDR 0x08
#define TLV_RESV_START 0x09 // Reserved Start
#define TLV_RESV_END 0x7e   // Reserved End
#define TLV_ORG_SPEC 0x7f   // Organization specific, we probably wont support any of these

/* CHASSIS ID SUBTYPES */

#define CHASSIS_ID_CHASSIS_COMPONENT 0x01
#define CHASSIS_ID_INTERFACE_ALIAS 0x02
#define CHASSIS_ID_PORT_COMPONANT 0x3
#define CHASSIS_ID_MAC_ADDRESS 0x4
#define CHASSIS_ID_NETWORK_ADDRESS 0x5
#define CHASSIS_ID_INTERFACE_NAME    0x6
#define CHASSIS_ID_LOCALLY_ASSIGNED  0x7

/* PORT ID SUBTYPES */

#define PORT_ID_INTERFACE_ALIAS  1
#define PORT_ID_PORT_COMPONENT   2
#define PORT_ID_MAC_ADDRESS      3
#define PORT_ID_NETWORK_ADDRESS  4
#define PORT_ID_INTERFACE_NAME   5
#define PORT_ID_AGENT_CIRCUIT_ID 6
#define PORT_ID_LOCALLY_ASSIGNED 7

/* SYSTEM CAPABILITIES */
#define SYSTEM_CAPABILITY_OTHER     1
#define SYSTEM_CAPABILITY_REPEATER  2
#define SYSTEM_CAPABILITY_BRIDGE    4
#define SYSTEM_CAPABILITY_WLAN      8
#define SYSTEM_CAPABILITY_ROUTER    16
#define SYSTEM_CAPABILITY_TELEPHONE 32
#define SYSTEM_CAPABILITY_DOCSIS    64
#define SYSTEM_CAPABILITY_STATION   128

/* MANAGEMENT ADDRESS IANA TYPES */
/* IANA Family Number Assignments */
/* http://www.iana.org/assignments/address-family-numbers */
#define IANA_RESERVED_LOW     0
#define IANA_IP               1
#define IANA_IP6              2
#define IANA_NSAP             3
#define IANA_HDLC             4
#define IANA_BBN_1822         5
#define IANA_802              6
#define IANA_E_163            7
#define IANA_E_164_ATM        8
#define IANA_F_69             9
#define IANA_X_121           10
#define IANA_IPX             11
#define IANA_APPLETALK       12
#define IANA_DECNET_IV       13
#define IANA_BANYAN_VINES    14
#define IANA_E_164_NSAP      15
#define IANA_DNS             16
#define IANA_DISTINGUISHED   17
#define IANA_AS_NUMBER       18
#define IANA_XTP_IPV4        19
#define IANA_XTP_IPV6        20
#define IANA_XTP_XTP         21
#define IANA_FIBRE_PORT_NAME 22
#define IANA_FIBRE_NODE_NAME 23
#define IANA_GWID            24
#define IANA_AFI_L2VPN       25
// Everything from 26 to 65534 is Unassigned
#define IANA_RESERVED_HIGH   65535
/* End IANA Family Number Assignments */

TLV *get_tlv(lldp_tlv_list *head, uint16_t tlv_type) 
{
    lldp_tlv_list * current = head;
    while(current->tlv != NULL) {
        if (current->tlv->type == tlv_type)
            return current->tlv;
        current = current->next;
    }
    return NULL;
}

void parse_lldp_packet(uint8_t *packet, lldp_tlv_list *head) {
    /*
     * 在TLV上迭代。分解TLV并将其存储在链接列表中。应在调用此函数之前进行验证 
     */

...

    do {
        tlv_header = (uint16_t *) &packet[calc_offset(tlv_offset)];
        current_tlv = (TLV *) calloc(1, sizeof(TLV));
        current_tlv->type = TLV_TYPE(htons(*tlv_header));
        current_tlv->length = TLV_LENGTH(htons(*tlv_header));

        if (current_tlv->length > 0) 
        {
            current_tlv->data = (uint8_t *) calloc(1, current_tlv->length);
            memcpy(current_tlv->data, &packet[calc_offset(tlv_offset) + sizeof(*tlv_header)], current_tlv->length);
        } else
            current_tlv->data = NULL;

        tlv_offset += sizeof(*tlv_header) + current_tlv->length;
        printf("Pushing TLV type : %d\n", current_tlv->type);
        tlv_list_push(head, current_tlv);

    } while(current_tlv->type != 0);
    ...
}
uint8_t * fetch_lldp_packet(char * ifname, time_t timeout) 
{
...

    if(packet == NULL) 
    {
        perror("Could not allocate memory for packet buffer");
        exit(EXIT_FAILURE);
    }

    memset(packet, 0, IP_MAXPACKET * sizeof(uint8_t));

    if ((sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0)
    {
        perror("socket() failed");
        exit (EXIT_FAILURE);
    }

    strncpy(ifr.ifr_name, ifname, strnlen(ifname, 20) + 1);

    ioctl(sock, SIOCGIFINDEX, &ifr);

    if(ifr.ifr_ifindex == 0) 
    {
        fprintf(stderr, "Interface %s does not seem to exist\n", ifname);
        exit(EXIT_FAILURE);
    }

    saddr_ll.sll_ifindex = ifr.ifr_ifindex;
    saddr_ll.sll_family = AF_PACKET;

    printf("Binding to interface %s, if_index %d\n", ifname, saddr_ll.sll_ifindex);

    if ((bind(sock, (struct sockaddr *) &saddr_ll, sizeof(saddr_ll))) < 0) 
    {
        perror("Bind failed");
        exit(EXIT_FAILURE);
    }

    ioctl(sock, SIOCGIFHWADDR, &ifr);

    memcpy(&mac_address, (void *) ifr.ifr_hwaddr.sa_data, 6);

    printf("HWADDR: %s\n", mac_address_fmt(mac_address));


    printf("Entering promiscuous mode on %s\n", ifname);

    ioctl(sock, SIOCGIFFLAGS, &ifr);

    ifr.ifr_flags |= IFF_PROMISC;

    ioctl(sock, SIOCSIFFLAGS, &ifr);

    recv_t(sock, packet, mac_address, timeout);

    printf("Disabling promiscuous mode\n");

    ifr.ifr_flags ^= IFF_PROMISC;

    ioctl(sock, SIOCSIFFLAGS, &ifr);

    printf("Closing socket\n");
    close(sock);

    return packet;
}
...
int main(int argc, char **argv)
{
...
    packet = (uint8_t *) malloc(IP_MAXPACKET * sizeof(uint8_t));
    packet_len = fread(packet, sizeof(uint8_t), IP_MAXPACKET, fd);

    if (packet_len < sizeof(ethernet_header)) 
    {
        printf("Packet is not large enough, need at least %zu bytes, only read: %lu", sizeof(ethernet_header), packet_len);
        exit(EXIT_FAILURE);
    }

    tlv_list = tlv_list_create();
...
    parse_lldp_packet(packet, tlv_list);

...

    current = tlv_list;

    if (current->tlv == NULL) 
    {
        log_info("No TLVs print");
        exit(EXIT_SUCCESS);
    }

    while (current->next != NULL) 
    {
        print_tlv(current->tlv);
        current = current->next;
    }
    print_tlv(current->tlv);
...
    tlv_list_destroy(tlv_list);
...
}

运行结果:
在这里插入图片描述
If you need the complete source code, please add the WeChat number (c17865354792)

总结

LLDP代表链路层发现协议。它是一个开放的IEEE标准(802.1AB)第2层协议。LLDP是CDP(思科发现协议)的开源替代方案,CDP也是一种设备发现协议,仅在思科制造的设备(路由器、网桥、访问服务器和交换机)上运行第2层(数据链路层)。

Welcome to follow WeChat official account【程序猿编码

参考:1.https://standards.ieee.org/ieee/802.1ABcu/7131/
2.https://www.cisco.com/c/dam/en/us/solutions/collateral/workforce-experience/digital-building/digital-building-partner-guide.pdf
3.rfc 4836
4.http://www.iana.org/assignments/address-family-numbers

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

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

相关文章

20个Java编程技巧

1. 把字符串常量放在前面 通过把字符串常量放在比较函数equals()比较项的左侧来防止偶然的 NullPointerException 从来都不是一个坏主意&#xff0c;就像这样&#xff1a; 这是毫无疑问的&#xff0c;把一种表达式转换成另一种更好的表达式&#xff0c;并不会失去什么。只要我…

mysql锁机制及MVCC底层原理

一、锁介绍 按性能可分为乐观锁&#xff08;适用于读多写少的情况下&#xff0c;如果是写多&#xff0c;导致过多cpu空转&#xff0c;影响性能&#xff09;和悲观锁&#xff08;适用于写多的情况&#xff09;按数据库操作粒度可分为表锁、页锁、行锁按数据库操作类型可分为读锁…

UE4/5动画系列(1.模板制作)

目录 动画模板制作 同步模板组制作 有模板做什么都方便&#xff0c;所以这里我们做一个动画蓝图的模板&#xff08;动物专用&#xff09; 动画模板制作 第一步创建一个动画蓝图的模板 然后找到第三人称的模板&#xff0c;将其模板的蓝图改名&#xff1a; 在动画蓝图的模板里…

团体程序设计天梯赛-练习集L2篇②

&#x1f680;欢迎来到本文&#x1f680; &#x1f349;个人简介&#xff1a;Hello大家好呀&#xff0c;我是陈童学&#xff0c;一个与你一样正在慢慢前行的普通人。 &#x1f3c0;个人主页&#xff1a;陈童学哦CSDN &#x1f4a1;所属专栏&#xff1a;PTA &#x1f381;希望各…

首个跨云元数据KV存储Xline正式进入CNCF沙箱

2023年6月13日&#xff0c;云原生计算基金会&#xff08;CNCF&#xff09;宣布Xline正式被纳入CNCF沙箱(Sandbox&#xff09;项目。Xline是由达坦科技&#xff08;DatenLord&#xff09;于2022年年底推出的开源项目&#xff0c;是一个用Rust语言写就的&#xff0c;用于元数据管…

hello算法笔记之图

一、图的基础知识 图是一种非线性数据结构&#xff0c;由「顶点 Vertex」和「边 Edge」组成。 1.图的类型&#xff1a; 根据边是否具有方向可以分为有向图&#xff0c;无向图 根据所有顶点是否连通可以分为连通图&#xff08;对于连通图&#xff0c;从某个顶点出发&#xf…

gdb系列-入门篇-day01

gdb基础命令 一个程序要被调试&#xff0c;编译的时候要加上-g选项&#xff0c;例如gcc -g … 先准备一个调试的小代码 #include <stdio.h>int hello() {printf("hello\n");return 0; }int main() {int a[5] {1,2,3,4,5};hello();for(int i0; i<5; i){pri…

springboot使用@Valid 和 @Validated 注解校验详解以及编写一个自定义全局异常类

package com.test.springvalid.config;import lombok.Data; import java.util.HashMap; import java.util.Map;/*** 通用返回结果&#xff0c;服务端响应的数据最终都会封装成此对象* param <T>*/ Data public class R<T> {private Integer code; //编码&#xff1…

Mybatis源码分析_Mapper接口是如何实例化的 (2)

我们在使用Springmybatis的时候&#xff0c;经常都是直接写一个接口和一个对应的 ***Mapper.xml文件&#xff0c;然后业务代码就可以直接注入这个接口了。它是如何做到的呢&#xff1f; 接口&#xff1a; xml 想搞清楚这个问题&#xff0c;那还是要从Mybatis底层源码进行分析的…

智能小车使用IIC屏幕做动作显示界面

一、简介 使用0.96寸IIC屏幕作为遥控动作的显示界面。 外设引脚 stm32f103c8t6单片机IIC引脚有两组 使用I2C1&#xff0c;对应的时钟与数据线分别为PB6、PB7。 IIC屏幕指令 // OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panel // OLED_WR_Byte(0x00,OLED_CMD);//---se…

07- c语言指针 (C语言)

一 指针的引入 1、一般把内存中的一个字节称为一个内存单元。 2、为了正确地访问这些内存单元&#xff0c;必须为每个内存单元编上号。根据一个内存单元的编号即可准确地找到该内存单元。内存单元的编号也叫做地址&#xff0c;通常也把这个地址称为指针。 3、如果在程序中定义…

车载网络测试 - CANCANFD - 基础篇_03

十、发送方式与过滤方式 1、广播发送及规则 我们以小组讨论现场为例来说明CAN总线广播发送规则&#xff1a; 1&#xff09;一个房间代表同一路CAN总线&#xff0c;每一个小组代表一个CAN Node&#xff0c;每一个小组成员发言代表发送一帧CAN报文&#xff0c;对所有的小组成员进…

生成对抗网络

1 GAN基本概念 1.1 GAN介绍 GAN的英文全称是Generative Adversarial Network&#xff0c;中文名是生成对抗网络。它由两个部分组成&#xff0c;生成器和鉴别器&#xff08;又称判别器&#xff09;&#xff0c;生成网络&#xff08;Generator&#xff09;负责生成模拟数据&…

【Python】异常处理 ④ ( 异常处理 else 语句 | 异常处理 finally 语句 )

文章目录 一、Python 异常捕获 else 语句1、异常捕获 else 语句2、代码示例 - 没有触发 else 语句的情况3、代码示例 - 触发 else 语句的情况 二、Python 异常捕获 finally 语句1、异常捕获 finally 语句2、代码示例 - 出现异常后执行 finally 语句 一、Python 异常捕获 else 语…

展示和标注图像:探索Gradio AnnotatedImage模块的功能

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

代码生成器原理分析

代码生成器原理分析 理解代码生成器的需求和实现思路掌握freemaker的使用 理解数据库中的元数据完成环境搭建工作 浅谈代码生成器 概述 在项目开发过程中&#xff0c;关注点更多是在业务功能的开发及保证业务流程的正确性上&#xff0c;对于重复性的代码编写占据了程 序员…

指标综合评价(定性指标定量化、指标正相关化、赋权重)

目录 一、定性指标定量化 二、将指标同型化 线性比例变换法 极差变换法 二、评价指标赋予权重 三、综合评价 战斗机性能的综合评价问题 例&#xff1a;战斗机的性能指标主要包括最大速度、飞行半径、最大负载、隐身性能、垂直起降性能、可靠性、灵敏度等指标和相关费用。…

Vue+Element UI 生鲜管理系统简介及项目搭建,页面布局(一)

文章目录 浅谈一、背景二、搭建创建vue项目vue项目结构简介安装Element UI库安装axios安装querystring安装normalize.css安装echarts运行删除无用组件基础css样式导入 三、页面布局配置路由布局flex布局&#xff08;弹性盒子&#xff09;固定布局固定布局配置路由 浅谈 自从入…

【Rust】2、实战:文件、网络、时间、进程-线程-容器、内核、信号-中断-异常

文章目录 七、文件和存储7.2 serde 与 bincode 序列化7.3 实现一个 hexdump7.4 操作文件7.4.1 打开文件7.4.2 用 std::fs::Path 交互 7.5 基于 append 模式实现 kv数据库7.5.1 kv 模型7.5.2 命令行接口 7.6 前端代码7.6.1 用条件编译定制要编译的内容 7.7 核心&#xff1a;LIBA…

【Java高级语法】(十五)lambda表达式:给你一颗语法糖Lambda,解析函数式编程的杰作~

Java高级语法详解之lambda表达式 1️⃣ 概念2️⃣ 优势和缺点3️⃣ 使用3.1 语法结构3.2 案例3.2.1 无参Lambda3.2.2 带有一个参数3.2.3 带有多个参数3.2.4 方法引用的简化形式 4️⃣ 应用场景5️⃣ 优化技巧6️⃣ 原理7️⃣ 注意性能问题&#x1f33e; 总结 1️⃣ 概念 Java …