【网络进阶】Posix API与网络协议栈(五)

news2024/11/25 3:08:04

文章目录

    • 1. ARP协议
      • 1.1 ARP协议的定义
      • 1.2 ARP协议的工作过程
      • 1.3 ARP协议的数据结构
      • 1.4 ARP欺骗
      • 1.5 ARP协议的局限性
      • 1.6 ARP协议与Posix API的关系
    • 2. ARP协议例子
    • 3. ICMP协议
      • 3.1 ICMP协议的定义
      • 3.2 ICMP协议的类型
      • 3.3 ICMP协议的工作原理
      • 3.4 ICMP协议的应用
      • 3.5 ICMP协议的局限性和安全性
      • 3.6 ICMP协议与Posix API的关系
    • 4. ICMP协议例子
    • 5. 用户态网络协议栈
      • 5.1 用户态网络协议栈的定义
      • 5.2 用户态网络协议栈的优点
      • 5.3 用户态网络协议栈的缺点
      • 5.4 用户态网络协议栈的例子
      • 5.5 用户态网络协议栈与Posix API的关
    • 6. TCP协议演示
      • 6.1 TCP协议的基础知识
      • 6.2 TCP的三次握手
      • 6.3 TCP的四次挥手
      • 6.4 TCP协议与Posix API的关系
    • 7. TCP协议栈实现
      • 7.1 TCP协议栈的层级结构
      • 7.2 TCP协议栈的主要模块
      • 7.3 TCP协议栈的数据流
      • 7.4 TCP协议栈与Posix API的关系

1. ARP协议

在这里插入图片描述

1.1 ARP协议的定义

ARP协议,即地址解析协议(Address Resolution Protocol),是一个在局域网中实现IP地址到MAC地址转换的协议。ARP是工作在OSI模型的数据链路层和网络层之间的一种协议。

1.2 ARP协议的工作过程

ARP的工作过程主要包括四个步骤:ARP请求、ARP应答、ARP缓存、ARP刷新。

  1. ARP请求:一台主机向局域网内广播一个ARP请求,请求包含发送主机的IP地址和MAC地址,以及目标主机的IP地址,但不包含目标主机的MAC地址。
  2. ARP应答:所有收到ARP请求的主机都会检查自己的IP地址与ARP请求中的目标IP地址是否相同。如果相同,则该主机会发送ARP应答,该应答包含自己的IP地址和MAC地址。
  3. ARP缓存:发送ARP请求的主机会保存收到的ARP应答中的IP地址和MAC地址映射信息,这个保存过程叫做ARP缓存。这样,下次需要发送数据时,就可以直接从ARP缓存中查找目标MAC地址,而不用再次发出ARP请求。
  4. ARP刷新:由于网络状况可能发生变化,ARP缓存的有效期通常不会很长,一段时间后,ARP缓存中的映射关系需要被刷新。

1.3 ARP协议的数据结构

ARP报文主要由硬件类型、协议类型、硬件地址长度、协议地址长度、操作字段、发送者硬件地址、发送者协议地址、目标硬件地址、目标协议地址等部分组成。特别是操作字段,它用来标识ARP报文的类型,如果值为1,则表示这是一个ARP请求;如果值为2,则表示这是一个ARP应答。

1.4 ARP欺骗

ARP欺骗(ARP Spoofing)是一种网络攻击手段,攻击者通过发送伪造的ARP应答,使得其他主机的ARP缓存中保存了错误的IP地址和MAC地址映射信息,从而实现了对网络数据的劫持或者篡改。

1.5 ARP协议的局限性

ARP协议虽然简洁易用,但也有一些局限性。例如,ARP协议只能用于IPv4网络,对于IPv6网络,ARP协议已经被NDP(Neighbor Discovery Protocol)所取代。此外,由于ARP协议的安全性较低,容易受到ARP欺骗的攻击,所以在一些需要高安全性的网络中,可能需要采用其他方式来获取MAC地址。

1.6 ARP协议与Posix API的关系

在Posix API中,并没有直接操作ARP协议的接口,通常ARP协议的操作是由操作系统的网络栈自动完成的。但是,通过使用raw socket,我们可以直接操作数据链路层的数据,从而可以发送和接收ARP报文。同时,我们也可以通过ioctl函数获取和设置ARP缓存的内容。

2. ARP协议例子

下面是一个简单的ARP请求和响应的例子:

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/if_ether.h>
#include <net/if.h>
#include <netpacket/packet.h>

#define ARP_REQUEST 1
#define ARP_REPLY 2

typedef struct arp_header {
    uint16_t hardware_type;
    uint16_t protocol_type;
    uint8_t hardware_len;
    uint8_t protocol_len;
    uint16_t opcode;
    uint8_t sender_mac[6];
    uint8_t sender_ip[4];
    uint8_t target_mac[6];
    uint8_t target_ip[4];
} arp_header_t;

void fill_arp_request(arp_header_t *arp) {
    arp->hardware_type = htons(1);
    arp->protocol_type = htons(ETH_P_IP);
    arp->hardware_len = 6;
    arp->protocol_len = 4;
    arp->opcode = htons(ARP_REQUEST);
    //填写你的MAC地址和IP地址
    memcpy(arp->sender_mac, "\xaa\xbb\xcc\xdd\xee\xff", 6);
    memcpy(arp->sender_ip, "\xc0\xa8\x01\x0a", 4); // 192.168.1.10
    //填写目标MAC地址和IP地址
    memcpy(arp->target_mac, "\x00\x00\x00\x00\x00\x00", 6); 
    memcpy(arp->target_ip, "\xc0\xa8\x01\x14", 4); // 192.168.1.20
}

int main() {
    int sd;
    char buffer[60];
    struct sockaddr_ll socket_address;

    //建立原始套接字
    sd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
    if (sd == -1) {
        perror("socket creation failed");
        return -1;
    }

    //清空缓冲区和套接字地址
    memset(buffer, 0x00, 60);
    memset(&socket_address, 0x00, sizeof(socket_address));

    //填充Ethernet帧头部
    struct ethhdr *eth = (struct ethhdr *)buffer;
    eth->h_proto = htons(ETH_P_ARP);
    //填写你的MAC地址
    memcpy(eth->h_source, "\xaa\xbb\xcc\xdd\xee\xff", 6);
    //填写目标MAC地址
    memcpy(eth->h_dest, "\xff\xff\xff\xff\xff\xff", 6);

    //填充ARP请求
    arp_header_t *arp = (arp_header_t *)(buffer + 14);
    fill_arp_request(arp);

    //设置目标地址
    socket_address.sll_family = AF_PACKET;
    socket_address.sll_protocol = htons(ETH_P_ARP);
    socket_address.sll_ifindex = if_nametoindex("eth0");

    //发送ARP请求
    if (sendto(sd, buffer, 42, 0, (struct sockaddr*)&socket_address, sizeof(socket_address)) == -1) {
        perror("send failed");
        return -1;
    }

    return 0;
}

上面的程序首先创建了一个原始套接字,然后填充了一个Ethernet帧和ARP请求,最后将其发送到网络中。这是一个非常简单的ARP请求,用于查询给定IP地址(192.168.1.20)对应的MAC地址。

在ARP头部中,hardware_type字段指的是硬件类型,protocol_type字段指的是协议类型,hardware_len字段和protocol_len字段分别代表硬件地址和协议地址的长度。opcode字段指示ARP消息的类型,可以是ARP请求或ARP回复。

3. ICMP协议

在这里插入图片描述

3.1 ICMP协议的定义

Internet控制消息协议(ICMP,Internet Control Message Protocol)是TCP/IP协议族的一部分,它是网络层的一个重要协议,主要用于网络设备之间发送控制消息。ICMP常用于处理网络通信中的错误情况,并进行相关的诊断。

3.2 ICMP协议的类型

ICMP消息有很多种类型,包括但不限于:目标不可达(Type 3)、源抑制(Type 4)、重定向(Type 5)、回显请求和回显应答(Type 8 和 Type 0)、时间超过(Type 11)、参数问题(Type 12)、时间戳请求和时间戳应答(Type 13 和 Type 14)等。

3.3 ICMP协议的工作原理

以“回显请求”和“回显应答”(也就是我们常说的ping命令)为例:

  1. 发送端发送一个带有特定标识符和序列号的“回显请求”ICMP消息到目标IP地址。
  2. 如果目标IP地址的主机可达,它会回送一个带有相同标识符和序列号的“回显应答”ICMP消息。
  3. 发送端在收到“回显应答”消息后,会计算发送请求和接收应答之间的时间差,这个时间就是我们常说的网络延迟。

3.4 ICMP协议的应用

ICMP协议主要用于网络诊断。常见的应用如下:

  • ping命令:用于测试目标主机是否可达,以及网络延迟。
  • traceroute命令:用于跟踪数据包从源主机到目标主机的路由路径。
  • 路由器和网关:可以利用ICMP发送错误消息,如“目标不可达”、“重定向”等。

3.5 ICMP协议的局限性和安全性

ICMP协议提供了一种处理和报告网络问题的方法,但它也有一些局限性和安全问题。

  1. 局限性:ICMP不能提供关于网络问题的详细信息,例如,它不能诊断是哪个应用程序或哪个服务导致的网络问题。
  2. 安全问题:由于ICMP可以用于发现网络的结构和活动,因此它可能会被用于进行网络侦查和拒绝服务(DoS)攻击。

3.6 ICMP协议与Posix API的关系

在Posix API中,我们可以通过使用raw socket和setsockopt函数来发送和接收ICMP消息。例如,我们可以创建一个raw socket,然后使用setsockopt函数来设置ICMP的类型和代码,最后使用sendto函数来发送ICMP消息。在接收ICMP消息时,我们可以使用recvfrom函数来获取ICMP消息的内容和来源地址。

4. ICMP协议例子

如下是一个简单的ICMP echo请求(即ping)的例子。这个程序会向指定的IP地址发送ICMP echo请求,并接收并打印来自那个IP地址的ICMP echo回应:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <arpa/inet.h>

#define PACKET_SIZE 4096

unsigned short checksum(void *b, int len) {
    unsigned short *buf = b;
    unsigned int sum = 0;
    unsigned short result;

    for (sum = 0; len > 1; len -= 2)
        sum += *buf++;
    if (len == 1)
        sum += *(unsigned char*)buf;
    sum = (sum >> 16) + (sum & 0xFFFF);
    sum += (sum >> 16);
    result = ~sum;
    return result;
}

void ping(struct sockaddr_in *addr) {
    const int val = 255;
    int i, sockfd;
    struct icmp sendicmp;
    struct sockaddr_in from;
    char recvbuf[PACKET_SIZE] = {0};

    sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if (sockfd < 0) {
        printf("socket() failed\n");
        return;
    }

    setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &val, sizeof(val));

    sendicmp.type = ICMP_ECHO;
    sendicmp.code = 0;
    sendicmp.checksum = 0;
    sendicmp.un.echo.id = getpid();
    sendicmp.un.echo.sequence = 1;
    sendicmp.checksum = checksum(&sendicmp, sizeof(sendicmp));

    if (sendto(sockfd, &sendicmp, sizeof(sendicmp), 0, (struct sockaddr *)addr, sizeof(struct sockaddr_in)) < 0) {
        printf("sendto() failed\n");
        return;
    }

    struct sockaddr_in from_addr;
    socklen_t from_len = sizeof(from_addr);

    if (recvfrom(sockfd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr*)&from_addr, &from_len) < 0) {
        printf("recvfrom() failed\n");
        return;
    }

    struct ip *iph = (struct ip *)recvbuf;
    struct icmp *icmph = (struct icmp *)(recvbuf + (iph->ip_hl<<2));

    if (icmph->icmp_type == ICMP_ECHOREPLY) {
        printf("Received ICMP echo reply from %s\n", inet_ntoa(from.sin_addr));
    } else {
        printf("Received non-echo reply packet\n");
    }
}

int main() {
    struct sockaddr_in addr_ping, *addr;
    addr = &addr_ping;
    memset(addr, 0, sizeof(struct sockaddr_in));
    addr->sin_family = AF_INET;
    addr->sin_addr.s_addr = inet_addr("8.8.8.8"); // Google DNS server
    ping(addr);
    return 0;
}

上述程序的主体部分是ping函数,该函数发送一个ICMP echo请求并接收回应。ping函数首先创建一个原始套接字,并设置接收缓冲区大小。

然后,创建一个ICMP echo请求消息,包括类型(ICMP_ECHO)、代码(0)、校验和、ID(当前进程的PID)和序列号。计算校验和并将其写入到消息中。

使用sendto函数将ICMP消息发送到指定的目标地址。然后,使用recvfrom函数接收回应。如果接收到的ICMP消息的类型是ICMP_ECHOREPLY,说明接收到了一个ICMP echo回应。打印出源地址,并返回。

主函数中设定目标地址为"8.8.8.8",这是Google的公共DNS服务器,通常可用于ping测试。

5. 用户态网络协议栈

5.1 用户态网络协议栈的定义

用户态网络协议栈是指运行在用户空间的网络协议栈。传统的网络协议栈,如TCP/IP协议栈,通常运行在内核空间,而用户态网络协议栈则是将网络协议栈的实现从内核空间转移到了用户空间。

5.2 用户态网络协议栈的优点

  1. 易于开发和调试:用户态网络协议栈可以直接利用用户空间的各种开发工具和库,可以更方便地进行开发和调试。
  2. 可扩展性:用户态网络协议栈可以更灵活地扩展和修改,可以更好地适应各种特定的应用需求。
  3. 高性能:用户态网络协议栈可以绕过内核的系统调用和上下文切换,直接访问网络硬件,从而提高网络处理的效率。

5.3 用户态网络协议栈的缺点

  1. 需要专门的驱动支持:由于用户态网络协议栈直接访问网络硬件,因此需要网络设备驱动提供相应的支持。
  2. 安全性问题:用户态网络协议栈直接访问网络硬件,如果没有恰当的隔离和权限控制,可能会带来安全问题。
  3. 兼容性问题:用户态网络协议栈可能需要修改应用程序的代码,以适应其API,这可能会带来一些兼容性问题。

5.4 用户态网络协议栈的例子

目前,已经有一些用户态网络协议栈的实现,如DPDK (Data Plane Development Kit),Seastar等。这些用户态网络协议栈通常提供了一套完整的API,可以让应用程序直接进行网络编程,而无需依赖内核的网络服务。

5.5 用户态网络协议栈与Posix API的关

用户态网络协议栈通常需要使用其自己的API来进行网络编程,这些API可能与Posix API有所不同。然而,一些用户态网络协议栈,如Seastar,提供了与Posix API相兼容的接口,从而使得已有的基于Posix API的应用程序可以更容易地迁移到用户态网络协议栈上。

6. TCP协议演示

6.1 TCP协议的基础知识

传输控制协议(TCP,Transmission Control Protocol)是一个面向连接的、可靠的、基于字节流的传输层通信协议,它在互联网协议(IP)之上提供了一个稳定且可靠的数据传输服务。

TCP协议包含以下主要特性:

  • 面向连接:在数据传输之前,必须先在发送端和接收端之间建立一个连接。
  • 可靠传输:通过序号、确认应答、重传、流量控制等机制,确保数据可靠地从发送端传输到接收端。
  • 流量控制和拥塞控制:通过滑动窗口、慢启动、拥塞避免、快重传和快恢复等机制,控制数据的传输速率,防止网络拥塞。

6.2 TCP的三次握手

TCP连接的建立过程通常被称为“三次握手”:

  1. 第一次握手:客户端发送一个SYN包(序号为X)到服务器,请求建立连接。
  2. 第二次握手:服务器收到SYN包后,回复一个SYN-ACK包(序号为Y,确认号为X+1)到客户端,确认收到SYN包。
  3. 第三次握手:客户端收到SYN-ACK包后,回复一个ACK包(确认号为Y+1)到服务器,确认收到SYN-ACK包。

6.3 TCP的四次挥手

TCP连接的关闭过程通常被称为“四次挥手”:

  1. 第一次挥手:主动关闭的一方(假设为客户端)发送一个FIN包(序号为M)到对方,表示不再发送数据。
  2. 第二次挥手:被动关闭的一方(假设为服务器)收到FIN包后,回复一个ACK包(确认号为M+1)到客户端,确认收到FIN包。
  3. 第三次挥手:被动关闭的一方在所有数据发送完毕后,发送一个FIN包(序号为N)到对方,表示不再发送数据。
  4. 第四次挥手:主动关闭的一方收到FIN包后,回复一个ACK包(确认号为N+1)到被动关闭的一方,确认收到FIN包。

6.4 TCP协议与Posix API的关系

在Posix API中,我们可以使用如下几个主要的函数来实现TCP通信:

  • socket函数:创建一个新的套接字。
  • bind函数:将套接字绑定到一个特定的地址和端口上。
  • listen函数:在套接字上监听连接请求。
  • connect函数:向一个特定的地址和端口发起连接请求。
  • accept函数:接受一个连接请求,并返回一个新的套接字来处理这个连接。
  • send和recv函数:在已建立的连接上发送和接收数据。
  • close函数:关闭一个套接字和相关的连接。

这些函数的使用方法以及它们如何与TCP协议交互是Posix API网络编程的核心内容。

7. TCP协议栈实现

7.1 TCP协议栈的层级结构

在实现TCP协议栈时,我们通常会根据协议的层级结构来组织代码,每一层协议都对应一个或多个模块。比如:

  • 应用层:这一层包含了HTTP、FTP、SMTP等应用协议的处理模块。
  • 传输层:这一层主要实现了TCP和UDP协议。
  • 网络层:这一层主要实现了IP协议,包括IP地址处理、路由选择、IP数据包的封装和解封装等功能。
  • 数据链路层和物理层:这两层通常由操作系统和网络设备驱动来实现,应用程序一般不直接处理这两层的协议。

7.2 TCP协议栈的主要模块

在TCP协议栈中,主要有以下几个模块:

  • 套接字管理模块:负责管理套接字的创建、绑定、监听、连接、关闭等操作。
  • 连接管理模块:负责TCP连接的建立、维护和关闭,包括三次握手、四次挥手、状态转换等功能。
  • 数据传输模块:负责数据的发送和接收,包括数据的封装和解封装、序号和确认应答的处理、重传机制、滑动窗口等功能。
  • 拥塞控制模块:负责控制数据的发送速率,防止网络拥塞,包括慢启动、拥塞避免、快重传和快恢复等机制。

7.3 TCP协议栈的数据流

在TCP协议栈中,数据的流动路径如下:

  1. 应用程序通过调用send函数,将数据发送给传输层。
  2. 传输层接收到数据后,根据目标IP地址和端口号,将数据封装成一个或多个TCP数据包,并将它们发送到网络层。
  3. 网络层接收到TCP数据包后,根据目标IP地址,将数据包封装成一个或多个IP数据包,并将它们发送到数据链路层。
  4. 数据链路层接收到IP数据包后,将其发送到物理网络中。

接收数据的流程与发送数据的流程相反,从物理网络开始,经过数据链路层、网络层、传输层,最后到达应用程序。

7.4 TCP协议栈与Posix API的关系

在TCP协议栈中,Posix API作为应用程序和传输层之间的接口。应用程序通过调用Posix API来发送和接收数据,而TCP协议栈则负责实现这些API,并根据TCP协议的规则来处理数据的传输。

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

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

相关文章

软考:中级软件设计师:操作系统,进程管理,前趋图,进程同步互斥,PV操作,

软考&#xff1a;中级软件设计师:操作系统 提示&#xff1a;系列被面试官问的问题&#xff0c;我自己当时不会&#xff0c;所以下来自己复盘一下&#xff0c;认真学习和总结&#xff0c;以应对未来更多的可能性 关于互联网大厂的笔试面试&#xff0c;都是需要细心准备的 &…

Openlayers实战:地图上显示经纬度坐标

Openlayers地图中,鼠标移动,其位置的经纬度坐会经常显示在页面中。 在我们的实战课程里,详细讲一下其做法,成为一个主力的应用。 效果图 源代码 /* * @Author: 大剑师兰特(xiaozhuanlan),还是大剑师兰特(CSDN) * @此源代码版权归大剑师兰特所有,可供学习或商业项目…

vue中如何引入插件并使用

Vue中的插件类型 vue中有大致有三种类型的插件&#xff0c;第三方插件、基于vue开发的插件及基于vue开发的组件 第三方插件 如&#xff1a;jquery、moment.js、aixos、Highcharts等 注意&#xff1a;Highcharts也有基于vue开发的插件版本&#xff0c;具体使用方法参见下文 …

C++中的类

1、类和对象 C中通过class定义类 class A {int a; }; // 定义一个A类型的类通过类来定义对象 A a; // 定义一个A类型的对象类是一张蓝图&#xff0c;是抽象的。而对象是根据蓝图真正建造出来的建筑&#xff0c;是具象的。 对象是类的实体化 2、类的限制修饰符 类有三种修…

xmrig病毒删除

删除病毒 [rootnode101 .mint-xmr]# top | headPID USER PR NI VIRT RES SHR S %CPU %MEM TIME COMMAND 15870 root 20 0 4597844 2.0g 4 S 1017 3.3 52:05.95 xmrig[rootnode101 .mint-xmr]# ll /proc/15870/exe lrwxrwxrwx. 1 root ro…

【C#】SqlBulkCopy批量添加注意DataTable必须与表列顺序一致,否则报错,以及关闭自增列

前篇文章在测试一个批量添加的操作&#xff0c;发现一致添加不成功&#xff0c;最后分析是字段列顺序不一致的问题 目录 1、列名不一致1.1、错误信息1.2、解决方法 2、关闭自增列2.1、不包含列2.2、特性关闭 1、列名不一致 1.1、错误信息 在调试时&#xff0c;一致提示如下错…

基于 Flink SQL CDC的实时数据同步方案

基于 Flink SQL CDC的实时数据同步方案http://www.dreamwu.com/post-1594.html

iframe编码为utf-8.嵌入页面为gb2312 ,word导出默认为gb2312 格式

使用记事本打开html&#xff0c;另存为&#xff0c;保存类型选择&#xff1a;"所有文件"、编码选择&#xff1a;“UTF-8”打开保存后文件编码类型改成utf-8 第一个步骤是为了把内容改成utf-8&#xff0c;然后直接执行第二步改编码可能会报乱码

解决printJS打印问题汇总

目录 一、打印预览表格列不全&#xff08;Element的el-table组件&#xff09; 1、打印设置“打印缩放” 2、修改el——table的底层代码&#xff08;如果页面上有多个表格慎用&#xff09; 一、打印预览表格列不全&#xff08;Element的el-table组件&#xff09; 问题描述&a…

简单的手机记事本app怎么查看提醒列表?

很多人平时都有随手记事的习惯&#xff0c;在记录事情的时候使用手机上的记事本app是一个不错的选择。有的记事本功能比较完善&#xff0c;不但能记事还能设置提醒&#xff0c;当有多条提醒内容存在时&#xff0c;简单的手机记事本app怎么查看提醒列表呢&#xff1f;以iPhone手…

Easyexcel 导出数据 一对多关系导出数据集合

客户要求 要求导出的表格如图 实现这样表格 很多人会想到动态表头&#xff0c;easypoi可以直接实现&#xff0c;但是我用的是easyexcel,而easyexcel自身并没有提供自动合并的功能所以还是需要自己来合并。 代码如下 首先我们来看下将嵌套数据平铺&#xff0c;不进行合并导出…

解决github打不开的方法(亲测有效)

网上提供了很多针对github打开慢的解决方案&#xff0c;什么又是改host文件&#xff0c;又是下载杂七杂八的加速器等等&#xff0c;其实效果并不好&#xff0c;微软商城已有对应的软件可以解决该问题&#xff0c;获取路径更为安全。 目录 安装Watt Toolkit找不到Microsoft Stor…

Aduc7126的PLA模块

PLA 一、PLA结构讲解 PLA是Aduc7126内部的可编辑逻辑阵列&#xff0c;Aduc7126总共有16个element&#xff0c;分为两组&#xff0c;如下图所示。 下图是PLA的其中一个element结构图&#xff0c;按照由左至右进行讲解&#xff1a; 左边MUX0、MUX1、MUX2、MUX3都是选择器&#…

将 InputStream 流转成 MultipartFile

MultipartFile是一个接口, 有一个MockMultipartFile实现类,里面有构造方法可以直接将输入流转为MutipartFile对象: MultipartFile File new MockMultipartFile(filename, file.getName(), file.getContentType(), fileStream); 使用MockMultipartFile类, 项目需要导入org.sp…

maven配置问题

maven配置问题 Error running ‘项目名 [install]’: No valid Maven installation No valid Maven installation found. Either set the home directory in the configuration dialog or set the M2_HOME environment variable on your system. 解决方法&#xff1a; 依次检…

Echarts柱状图循环配色多色彩

话不多说&#xff0c;直接上配置案例&#xff0c;欢迎留言分享交流 option {xAxis: {type: category,data: [Mon, Tue, Wed, Thu, Fri, Sat, Sun,"y","q","y","u"]},yAxis: {type: value},series: [{itemStyle: {normal: {// barBorde…

华为OD机试真题 Python 实现【数组的中心位置】【2023Q1 100分】,附详细解题思路

目录 一、题目描述二、输入描述三、输出描述四、解题思路五、Python算法源码六、效果展示1、输入2、输出 一、题目描述 给你一个整数数组nums&#xff0c;请计算数组的中心位置&#xff0c;数组的中心位置是数组的一个下标&#xff0c;其左侧所有元素相乘的积等于右侧所有元素…

Fiddler 工具的使用

文章目录 01 Fiddler 工具介绍1. 下载与安装2. Fiddler 工具界面介绍3. Fiddler 工具的工作原理 02 手工调用 HTTP 接口1. 发送HTTP请求2. 查看返回数据包 03 获取 PC 端的网络数据包04 获取手机端的网络数据包05 截包与改包场景一&#xff1a;截断请求数据&#xff0c;然后篡改…

一键安装和卸载docker及docker-compose

代码&#xff1a; #!/bin/bashSYSTEMD_PATH/usr/lib/systemd/system/docker.service DOCKER_FILEdocker-20.10.23.tgz DOCKER_COMPOSE_FILEdocker-compose-plugin-2.15.1-3.el8.x86_64.rpm RED\E[1;31m GREEN\E[1;32m YELOW\E[1;33m SHAN\E[1;31;5m RES\E[0mfunction install_…

项目中期检查会议和进度对接

1.召开中期项目检查会议&#xff0c;与团队成员和博士王锟对接进度。对整体项目表示满意接受&#xff0c;指出重点需要修改提升和进一步开发完善的部分&#xff0c;以增强系统的完整度、功能亮点和界面数量点。具体为 ①注重“highlight”&#xff0c;即布局凸显主题功能&…