网络设备驱动框架

news2024/9/27 5:58:01

1.框架

        

        1)网络协议接口层 向网络层协议提供统一的数据包收发接口,不论上层协议是ARP,还是IP,都通过dev_queue_xmit()函数发送数据,并通过netif_rx()函数接收数据。这一层的存在,使得上层协议独立于具体的设备。

        2)网络设备接口层 向协议接口层提供统一的用于描述具体网络设备属性和操作的结构体net_device,给结构体是设备驱动功能层中各函数的容器。实际上,网络设备接口层从宏观上规划了具体操作硬件设备驱动功能层的结构。

        3)设备驱动功能层的各函数是网络设备接口层net_device数据结构体的具体成员,是驱动网络设备硬件完成相应动作的程序,它通过hard_start_xmit()函数启动发送操作,并通过网络设备上的中断触发接收操作。

        4)网络设备与媒介层是完成数据包发送和接收的物理实现,包括网络适配器和具体的传输媒介,网络适配器被设备驱动功能层中的函数在物理上驱动。对Linux系统而言,网络设备和媒介都可以是虚拟的。

        在设计具体的网络设备驱动程序时,需要完成的主要工作是编写设备驱动功能层的相关函数以填充net_device数据结构体的内容并将net_device注册入内核。

2.网络协议接口层

        网络协议接口层最主要的功能是向上层协议提供透明的数据包发送和接收接口。当上层ARP或IP需要发送数据包时,它将调用网络协议接口层的dev_queue_xmit()函数发送数据包,同时续传递给函数一个指向struct sk_buff数据结构体的指针。dev_queue_xmit()函数原型为:

int dev_queue_xmit(struct sk_buff *skb);

        同样的,上层数据包的接收也通过向netif_rx()函数传递一个struct sk_buff数据结构体的指针来完成。netif_rx()函数原型为:

int netif_rx(struct sk_buff *skb);

2.1 sk_buff

        sk_buff结构体非常重要,它定义与include/linux.skbuff.h文件中,含义为“套接字缓冲区”,用于linux网络子系统中的各层之间传递数据,linux网络子系统数据传输的“中枢神经”。

        当发送数据包时,linux内核的网络处理模块必须建立一个包含要传输的数据包的sk_buff,然后将sk_buff递交给下层,各层在sk_buff中添加不同协议头直接交给网络设备发送。同样的,当网络设备从网络媒介上接收到数据包后,它将接收到的数据包转换为sk_buff数据结构体并传递给上层,各层剥去相应协议头直至交给用户。下面列出了sk_buff结构体的几个关键数据成员:

        网络协议栈中各层协议都可以通过对该结构的操作实现本层协议数据的添加或者删除。使用sk_buff结构避免了网络协议栈各层来回复制数据导致的效率低下。

         尤其注意的是head和end指向缓冲区的头部和尾部,而data和tail 指向实际数据的头部和尾部。每一层会在head和data之间填充协议头,或者在tail和end之间添加新的协议数据。

3.网络设备接口层

        网络设备接口层的只要功能是为千变万化的网络设备定义统一、抽象的数据结构体net_device结构体,以不变应万变,实现多种硬件在软件层次上的统一。 net_device结构体在内核中指代一个网络设备,它定义在include/linux/netdevice.h文件中,网路设备驱动程序只需要填充net_device的具体成员并注册net_device即可实现硬件操作函数与内核的挂接。 net_device是一个巨大的结构体,包含网络设备的属性和操作接口,下面介绍一些关键成员。

        每个网络设备都会有一个对应的实例,然后调用register_netdevie()(定义与文件net/core/dev.c)注册到系统中,注销可以通过unregister_netdevice()。

struct net_device {
    /* 设备名称,对应 ifconfig 输出的网卡名称,例如 eth0,字母代表网络设备的类型,数字代表此类网络设备的数量 */
    char            name[IFNAMSIZ];
    /* 名称hash */
    struct hlist_node    name_hlist;
    /*  别名,用于 SNMP 协议 */
    char             *ifalias;
    /*
        描述设备所用的共享内存,用于设备与内核沟通
        其初始化和访问只会在设备驱动程序内进行
    */
    unsigned long        mem_end;
    unsigned long        mem_start;
 
    /* 设备自有内存映射到I/O内存的起始地址 */
    unsigned long        base_addr;
 
    /*
        设备与内核对话的中断编号,此值可由多个设备共享
        驱动程序使用request_irq函数分配此变量,使用free_irq予以释放
    */
    int            irq;
 
    /* 侦测网络状态的改变次数 */
    atomic_t        carrier_changes;
 
    /*
        网络队列子系统使用的一组标识
        由__LINK_STATE_xxx标识
    */
    unsigned long        state;
 
    struct list_head    dev_list;
    struct list_head    napi_list;
    struct list_head    unreg_list;
    struct list_head    close_list;
 
    /* 当前设备所有协议的链表 */
    struct list_head    ptype_all;
    /* 当前设备特定协议的链表 */
    struct list_head    ptype_specific;
 
    struct {
        struct list_head upper;
        struct list_head lower;
    } adj_list;
 
    /*
        用于存在其他一些设备功能
        可报告适配卡的功能,以便与CPU通信
        使用NETIF_F_XXX标识功能特性
    */
    netdev_features_t    features;
    netdev_features_t    hw_features;
    netdev_features_t    wanted_features;
    netdev_features_t    vlan_features;
    netdev_features_t    hw_enc_features;
    netdev_features_t    mpls_features;
    netdev_features_t    gso_partial_features;
 
    /* 网络设备索引号 */
    int            ifindex;
 
    /* 设备组,默认都属于0组 */
    int            group;
 
    struct net_device_stats    stats;
 
    atomic_long_t        rx_dropped;
    atomic_long_t        tx_dropped;
    atomic_long_t        rx_nohandler;
 
#ifdef CONFIG_WIRELESS_EXT
    const struct iw_handler_def *wireless_handlers;
    struct iw_public_data    *wireless_data;
#endif
    /* 设备操作接口,主要用来操作网卡硬件 */
    const struct net_device_ops *netdev_ops;
    /* ethtool操作接口 */
    const struct ethtool_ops *ethtool_ops;
#ifdef CONFIG_NET_SWITCHDEV
    const struct switchdev_ops *switchdev_ops;
#endif
#ifdef CONFIG_NET_L3_MASTER_DEV
    const struct l3mdev_ops    *l3mdev_ops;
#endif
#if IS_ENABLED(CONFIG_IPV6)
    const struct ndisc_ops *ndisc_ops;
#endif
 
#ifdef CONFIG_XFRM
    const struct xfrmdev_ops *xfrmdev_ops;
#endif
 
    /* 头部一些操作,如链路层缓存,校验等 */
    const struct header_ops *header_ops;
 
    /* 标识接口特性,IFF_XXX,如IFF_UP */
    unsigned int        flags;
 
    /*
        用于存储用户空间不可见的标识
        由VLAN和Bridge虚拟设备使用
    */
    unsigned int        priv_flags;
 
    /* 几乎不使用,为了兼容保留 */
    unsigned short        gflags;
 
    /* 结构对齐填充 */
    unsigned short        padded;
 
    /* 与interface group mib中的IfOperStatus相关 */
    unsigned char        operstate;
    unsigned char        link_mode;
 
    /*
        接口使用的端口类型
    */
    unsigned char        if_port;
 
    /*
        设备使用的DMA通道
        并非所有设备都可以用DMA,有些总线不支持DMA
    */
    unsigned char        dma;
 
    /*
        最大传输单元,标识设备能处理帧的最大尺寸
        Ethernet-1500
    */
    unsigned int        mtu;
    /* 最小mtu,Ethernet-68 */
    unsigned int        min_mtu;
    /* 最大mut,Ethernet-65535 */
    unsigned int        max_mtu;
 
    /*     设备所属类型
        ARP模块中,用type判断接口的硬件地址类型
        以太网接口为ARPHRD_ETHER
    */
    unsigned short        type;
    /*
        设备头部长度
        Ethernet报头是ETH_HLEN=14字节
    */
    unsigned short        hard_header_len;
    unsigned char        min_header_len;
 
    /* 必须的头部空间 */
    unsigned short        needed_headroom;
    unsigned short        needed_tailroom;
 
    /* Interface address info. */
    /* 硬件地址,通常在初始化过程中从硬件读取 */
    unsigned char        perm_addr[MAX_ADDR_LEN];
    unsigned char        addr_assign_type;
    /* 硬件地址长度 */
    unsigned char        addr_len;
    unsigned short        neigh_priv_len;
    unsigned short          dev_id;
    unsigned short          dev_port;
    spinlock_t        addr_list_lock;
    /* 设备名赋值类型,如NET_NAME_UNKNOWN */
    unsigned char        name_assign_type;
    bool            uc_promisc;
    struct netdev_hw_addr_list    uc;
    struct netdev_hw_addr_list    mc;
    struct netdev_hw_addr_list    dev_addrs;
 
#ifdef CONFIG_SYSFS
    struct kset        *queues_kset;
#endif
    /* 混杂模式开启数量 */
    unsigned int        promiscuity;
 
    /* 非零值时,设备监听所有多播地址 */
    unsigned int        allmulti;
 
 
    /* Protocol-specific pointers */
/* 特定协议的指针 */
#if IS_ENABLED(CONFIG_VLAN_8021Q)
    struct vlan_info __rcu    *vlan_info;
#endif
#if IS_ENABLED(CONFIG_NET_DSA)
    struct dsa_switch_tree    *dsa_ptr;
#endif
#if IS_ENABLED(CONFIG_TIPC)
    struct tipc_bearer __rcu *tipc_ptr;
#endif
    void             *atalk_ptr;
    /* ip指向in_device结构 */
    struct in_device __rcu    *ip_ptr;
    struct dn_dev __rcu     *dn_ptr;
    struct inet6_dev __rcu    *ip6_ptr;
    void            *ax25_ptr;
    struct wireless_dev    *ieee80211_ptr;
    struct wpan_dev        *ieee802154_ptr;
#if IS_ENABLED(CONFIG_MPLS_ROUTING)
    struct mpls_dev __rcu    *mpls_ptr;
#endif
 
/*
 * Cache lines mostly used on receive path (including eth_type_trans())
 */
    /* Interface address info used in eth_type_trans() */
    unsigned char        *dev_addr;
 
#ifdef CONFIG_SYSFS
    /* 接收队列 */
    struct netdev_rx_queue    *_rx;
 
    /* 接收队列数 */
    unsigned int        num_rx_queues;
    unsigned int        real_num_rx_queues;
#endif
 
    struct bpf_prog __rcu    *xdp_prog;
    unsigned long        gro_flush_timeout;
 
    /* 如网桥等的收包回调 */
    rx_handler_func_t __rcu    *rx_handler;
    /* 回调参数 */
    void __rcu        *rx_handler_data;
 
#ifdef CONFIG_NET_CLS_ACT
    struct tcf_proto __rcu  *ingress_cl_list;
#endif
    struct netdev_queue __rcu *ingress_queue;
#ifdef CONFIG_NETFILTER_INGRESS
    /* netfilter入口 */
    struct nf_hook_entry __rcu *nf_hooks_ingress;
#endif
 
    /* 链路层广播地址 */
    unsigned char        broadcast[MAX_ADDR_LEN];
#ifdef CONFIG_RFS_ACCEL
    struct cpu_rmap        *rx_cpu_rmap;
#endif
    /* 接口索引hash */
    struct hlist_node    index_hlist;
 
/*
 * Cache lines mostly used on transmit path
 */
     /* 发送队列 */
    struct netdev_queue    *_tx ____cacheline_aligned_in_smp;
    /* 发送队列数 */
    unsigned int        num_tx_queues;
    unsigned int        real_num_tx_queues;
    /* 排队规则 */
    struct Qdisc        *qdisc;
#ifdef CONFIG_NET_SCHED
    DECLARE_HASHTABLE    (qdisc_hash, 4);
#endif
    /*
        可在设备发送队列中排队的最大数据包数
    */
    unsigned long        tx_queue_len;
    spinlock_t        tx_global_lock;
 
    /*     网络层确定传输超时,
        调用驱动程序tx_timeout接口的最短时间
    */
    int            watchdog_timeo;
 
#ifdef CONFIG_XPS
    struct xps_dev_maps __rcu *xps_maps;
#endif
#ifdef CONFIG_NET_CLS_ACT
    struct tcf_proto __rcu  *egress_cl_list;
#endif
 
    /* These may be needed for future network-power-down code. */
    /* watchdog定时器 */
    struct timer_list    watchdog_timer;
 
    /* 引用计数 */
    int __percpu        *pcpu_refcnt;
 
    /*     网络设备的注册和除名以两步进行,
        该字段用于处理第二步
    */
    struct list_head    todo_list;
 
    struct list_head    link_watch_list;
 
    /* 设备的注册状态 */
    enum { NETREG_UNINITIALIZED=0,
           NETREG_REGISTERED,    /* completed register_netdevice */
           NETREG_UNREGISTERING,    /* called unregister_netdevice */
           NETREG_UNREGISTERED,    /* completed unregister todo */
           NETREG_RELEASED,        /* called free_netdev */
           NETREG_DUMMY,        /* dummy device for NAPI poll */
    } reg_state:8;
 
    /* 设备要被释放标记 */
    bool dismantle;
 
    enum {
        RTNL_LINK_INITIALIZED,
        RTNL_LINK_INITIALIZING,
    } rtnl_link_state:16;
 
    bool needs_free_netdev;
    void (*priv_destructor)(struct net_device *dev);
 
#ifdef CONFIG_NETPOLL
    struct netpoll_info __rcu    *npinfo;
#endif
 
    possible_net_t            nd_net;
 
    /* mid-layer private */
    union {
        void                    *ml_priv;
        struct pcpu_lstats __percpu        *lstats;
        struct pcpu_sw_netstats __percpu    *tstats;
        struct pcpu_dstats __percpu        *dstats;
        struct pcpu_vstats __percpu        *vstats;
    };
 
#if IS_ENABLED(CONFIG_GARP)
    struct garp_port __rcu    *garp_port;
#endif
#if IS_ENABLED(CONFIG_MRP)
    struct mrp_port __rcu    *mrp_port;
#endif
 
    struct device        dev;
    const struct attribute_group *sysfs_groups[4];
    const struct attribute_group *sysfs_rx_queue_group;
 
    const struct rtnl_link_ops *rtnl_link_ops;
 
    /* for setting kernel sock attribute on TCP connection setup */
#define GSO_MAX_SIZE        65536
    unsigned int        gso_max_size;
#define GSO_MAX_SEGS        65535
    u16            gso_max_segs;
 
#ifdef CONFIG_DCB
    const struct dcbnl_rtnl_ops *dcbnl_ops;
#endif
    u8            num_tc;
    struct netdev_tc_txq    tc_to_txq[TC_MAX_QUEUE];
    u8            prio_tc_map[TC_BITMASK + 1];
 
#if IS_ENABLED(CONFIG_FCOE)
    unsigned int        fcoe_ddp_xid;
#endif
#if IS_ENABLED(CONFIG_CGROUP_NET_PRIO)
    struct netprio_map __rcu *priomap;
#endif
    struct phy_device    *phydev;
    struct lock_class_key    *qdisc_tx_busylock;
    struct lock_class_key    *qdisc_running_key;
    bool            proto_down;
};

3.1 设备操作函数

        网卡操作函数,如up,down,发包等(ifconfig XXX up,ifconfig XXX down等都是调用的这个结构体中的api)。net_device_ops的成员都是函数指针,是网络驱动程序实现的功能函数。

struct net_device_ops {
	int	(*ndo_init)(struct net_device *dev);	//提供网络设备的初始化、创建网络设备struct   net_device 数据结构实例、初始化struct net_device的相关数据														域如设备名、i/o端口地址、中断号、向内核注册设备
	void	 (*ndo_uninit)(struct net_device *dev);		//注销设备的时候用
	int	(*ndo_open)(struct net_device *dev);		//打开网络设备,主要注册的设备才能打开
	int	(*ndo_stop)(struct net_device *dev);		//停止网络设备,注销的时候调用和open相反
	netdev_tx_t	(*ndo_start_xmit) (struct sk_buff *skb,
	struct net_device *dev);				//初始化数据包发送过程,初始化成功后数据包就放入网络适配器的发哦送你个数据缓冲区
	u16(*ndo_select_queue)(struct net_device *dev,
	struct sk_buff *skb);					//当网络设备支持多个发送队列时用于选择发送队列
	................
}

        ndo_select_queue函数选择数据包发送队列。设备驱动程序通过函数ndo_start_xmit从任意发送队列中得到发送的数据包,通过函数static inline u16 skb_get_queue_mapping(const struct sk_buff *skb)得到数据包所在队列。

        ndo_open函数中需要做如下工作:

使能设备使用的硬件资源,申请 I/O 区域、中断和 DMA 通道等。

调用 Linux 内核提供的 netif_start_queue( )函数,激活设备发送队列。

        ndo_close函数需要完成如下工作:

调用 Linux 内核提供的 netif_stop_queue( )函数,停止设备传输包。

释放设备所使用的I/O区域、中断和 DMA 资源。

4.设备驱动功能层

        net_device结构体成员(属性和net_device_ops结构体中的函数指针)需要被设备驱动层赋予具体的数值和函数。对于具体的设备XXX,工程师应该编写相应的设备驱动功能层的函数,这些函数如xxx_open()、xxx-stop()、xxx_tx()等。

        由于网络数据报的接收可由中断引发,设备驱动功能层的另一个主体将是中断处理函数,它负责读取硬件上接收到的数据包并传送给上层协议,因此可能包含xxx_interrupt()和xxx_rx()函数,前者完成中断类型判断等基本工作,后者则需要完成数据包的生成及将其递交给上层等复杂工作。

        对于特定的设备,还可以定义相关的私有数据和操作,并封装成一个私有信息结构体xxx_private,让其指针赋值给net_device的私有成员。在xxx_private结构体中可包含设备的特殊属性和操作、自旋锁与限号量、定时器以及统计信息等,这都由工程师自定义。在驱动中,需用到私有数据的时候,则使用netdevixce.h中定义的接口:

static inline void *netdev_priv(const struct net_device *dev);

5.网络设备驱动的注册与注销

        网络设备的注册与注销由register_netdev()和unregister_netdev()函数完成,这两函数的原型为:

int register_netdev(struct net_device *dev);
void unregister_netdev(struct net_device *dev);

6.数据发送流程

        从网络设备驱动程序的结构分析可知,Linux网络子系统在发送数据包时,会调用驱动程序提供的hard_start_transmit()函数,该函数用于启动数据包的发送。在设备初始化的时候,这个函数指针需要初始化以指向设备的xxx_tx()函数。

        网络设备驱动完成数据包发送的流程如下:

        网络设备驱动程序从上层协议传递过来的sk_buff参数获得数据包的有效数据和长度,将有效数据放入临时缓冲区。

        对于以太网,如果有效数据的长度小于以太网冲突检测所需要数据帧的最小长度ETH_ZLEN,则给临时缓冲区的末尾填充0。

        设置硬件寄存器,驱使网络设备进行数据发送操作。

        完成以上3个步骤的网络设备驱动程序的数据包发送函数模板如下:

int xxx_tx(struct sk_buff *skb,struct net_device *dev)
{
    int len;
    char *data,shortpkt[ETH_ZLEN];
    if(xxx_send_available(...)) //发送队列为满,可以发送
    {
        //获得有效数据指针和长度 
        data = skb->data;
        len = skb->len;
        if(len < ETH_ZLEN) //如果帧长小于以太网帧最小长度,补0
        {
            memset(shortpkt,0,ETH_ZLEN);
            memcopy(shortpkt,skb->data,skb->len);
            len = ETH_ZLEN;
            data = shortpkt;
        }
    }
    //记录发送时间戳
    dev-.trans_start = jiffies;
    //设置硬件寄存器,让硬件把数据包发送出去
    if(avail){
        xxx_hw_tx(data,len,dev);
    }else{
        netif_stop_queue(dev);
        ...
    }
}

7.数据接收流

        网络设备接收数据的主要方法是有中断引发设备的中断处理函数,中断处理函数判断中断类型,如果为接收中断,则读取接收到的数据,分配sk_buffer数据结构和数据缓冲区,将接收到的数据复制到数据缓冲区,并调用netif_rx()函数将sk_buffer传递给上层协议。代码模板如下:

static void xxx_interupt(int irq,void *dev_id)
{
    ...
    switch(status &ISQ_EVENT_MASK)
    {
        case ISQ_RECEIVER_EVENT:
            //获取数据包
            xxx_rx(dev);
            //其他类型的中断
    }
}
 
static void xxx_rx(struct xxx_device *dev)
{
    ...
    length = get_rev_len(...);
    //分配新的套接字缓冲区
    skb = dev_alloc_skb(length + 2);
    skb_reserve(skb,2); //对其
    skb->dev = dev;
 
    //读取硬件上接收到的数据
    insw(ioaddr + RX_FRAME_PORT,skb_put(skb,length),length >> 1);
    if(length & 1)
        skb->data[length - 1] = inw(ioaddr + RX_FRAME_PORT);
    //获取上层协议类型
    skb->protocol = eth_type_trans(skb,dev);
    //把数据包交给上层
    netif_rx(skb);
    //记录接收时间戳
    dev->last_rx = jiffies;
    ...
}

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

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

相关文章

【总结】vim教程与详细命令总结,该来的躲不掉啊晕

B站|公众号&#xff1a;啥都会一点的研究生 目录写在前面vim的工作模式普通模式编辑模式命令模式命令大全&#xff0c;最详细&#xff08;建议收藏&#xff09;光标的移动插入模式 - 插入/追加文本编辑文本选择文本&#xff08;可视化模式&#xff09;可视化模式命令剪切, 复制…

【Selenium学习】Selenium 中特殊元素操作

1.鼠标定位操作鼠标悬停&#xff0c;即当光标与其名称表示的元素重叠时触发的事件&#xff0c;在 Selenium 中将键盘鼠标操作封装在 Action Chains 类中。Action Chains 类的主要应用场景为单击鼠标、双击鼠标、鼠标拖曳等。部分常用的方法使用分类如下&#xff1a;• click(on…

过滤器与拦截器

文章目录一、前言1、概述2、过滤器与拦截器异同2.1 简介2.2 异同2.3 总结3、Filters vs HandlerInterceptors二、过滤器1、概述2、生命周期2.1 生命周期概述2.2 基于函数回调实现原理3、自定义过滤器两种实现方式3.1 WebFilter注解注册3.2 过滤器&#xff08;配置类注册过滤器&…

vue2vue3常用语法(持续更新)

一、基础1. 指令指令描述v-if判断v-else-if判断后剩下的v-else判断后剩下的v-html渲染html文本格式v-text渲染文本v-for循环v-showdisplay&#xff1a;none/block切换v-model双向绑定v-bind(缩写&#xff1a;:)动态绑定v-on(缩写&#xff1a;)绑定dom事件(如点击事件)v-cloak解…

WMS AMS【Android Framework进阶】

1.简介 可以毫不夸张的说&#xff0c;android的framework层主要是由WMS、AMS还有View所构成&#xff0c;这三个模块穿插交互在整个framework中&#xff0c;掌握了它们之间的关系和每一个逻辑步骤&#xff0c;你对framework的了解至少有百分之五十 AMS是Android中最核心的服务…

设计模式:行为型设计模式

参考文章&#xff1a; 《设计模式》 《设计模式知识体系详解》 《DesignPatterns》 写在开头&#xff1a;本文为学习后的总结&#xff0c;可能有不到位的地方&#xff0c;错误的地方&#xff0c;欢迎各位指正。 前言 行为型模式是将不同的行为代码解耦&#xff0c;从而解决…

疯狂弹出请插入多卷集的最后一张磁盘窗口

整个人嘛了&#xff0c;今天插上U盘&#xff0c;跟tmd中了病毒一样&#xff0c; 屏幕疯狂弹出窗口&#xff0c; 提示请插入多卷集的最后一张磁盘&#xff01; 点确定之后他继续弹出&#xff0c;点取消它也继续弹出&#xff0c; 关掉一个又弹出来一个&#xff0c;妈的&#x…

系统编程中的进程的概念No.3【进程状态】

引言&#xff1a; 北京时间&#xff1a;2023/2/17/8:17&#xff0c;目前听着超能陆战队主题曲《Immortals》&#xff0c;感觉又要螺旋式升天&#xff0c;并且为我今天上午没课感到happy&#xff0c;所以继我们很久以前的关于进程的博客&#xff0c;今天我们就再来学习一下有关…

buuctf Web 下

9.[ACTF2020 新生赛]Exec 访问url&#xff1a; http://cc3c6c27-e2df-4665-baba-1d9a32dc963e.node3.buuoj.cn/ 首页如下&#xff1a; 直接ping ip可以得到结果 常见管道符 1、|&#xff08;就是按位或&#xff09;&#xff0c;直接执行|后面的语句 127.0.0.1 | cat /flag…

html 的相对路径和绝对路径

整篇文章是以 src 标签进行演示。 文章目录 一、相对路径 1、同级目录查找 2、上一级目录查找 3、下一级目录查找 二、绝对路径 一、相对路径 &#x1f475;相对路径&#xff1a;从当前目录开始查找。 1、同级目录查找 写法&#xff1a; 1.1.直接写文件名字&#xff1b;…

Linux之进程控制

一.进程创建 1.1 fork函数 我们创建进程的方式有./xxx和fork()两种 在linux中fork函数时非常重要的函数&#xff0c;它从已存在进程中创建一个新进程。新进程为子进程&#xff0c;而原进程为父进程。 #include <unistd.h> pid_t fork(void); 返回值&#xff1a;自进程…

Echarts实现多柱状图重叠重叠效果

有两种重叠效果: 1. 多个柱子重叠为一个 2. 多个柱子重叠为两组 第一种,图例: 这个灰色不是阴影哦, 是柱子. 1. 使用详解 (1) series.Z 折线图组件的所有图形的 z 值。控制图形的前后顺序。 z 值小的图形会被 z 值大的图形覆盖。z 相比 zlevel 优先级更低&#xff0c;而且不会…

GEE学习笔记 七十三:【GEE之Python版教程七】静态展示影像和动态展示影像

我们使用GEE在线编辑可以直接通过在线的网页可以加载展示我们计算的结果&#xff0c;而python版的GEE要展示我们的计算结果可能就比较麻烦。如果有同学看过GEE的python版API中可以找到一个类ee.mapclient&#xff0c;这个类的介绍是它是GEE官方通过Tk写的一个加载展示地图的类。…

【蓝桥日记⑤】2014第五届省赛(软件类)JavaA组❆答案解析

【蓝桥日记⑤】2014第五届省赛&#xff08;软件类&#xff09;JavaA组☃答案解析 文章目录【蓝桥日记⑤】2014第五届省赛&#xff08;软件类&#xff09;JavaA组☃答案解析1、猜年龄2、李白打酒3、神奇算式4、写日志5、锦标赛6、六角填数7、绳圈8、兰顿蚂蚁9、斐波那契10、波动…

Linux 操作系统原理 — NUMA 体系结构

目录 文章目录 目录NUMA 体系结构NUMA 的基本概念查看 Host 的 NUMA TopologyBash 脚本DPDK 脚步NUMA 体系结构 NUMA(Non-Uniform Memory Access,非一致性存储器访问)的设计理念是将 CPU 和 Main Memory 进行分区自治(Local NUMA node),又可以跨区合作(Remote NUMA nod…

操作系统 三(存储管理)

一、 存储系统的“金字塔”层次结构设计原理&#xff1a;cpu自身运算速度很快。内存、外存的访问速度受到限制各层次存储器的特点&#xff1a;1&#xff09;主存储器&#xff08;主存/内存/可执行存储器&#xff09;保存进程运行时的程序和数据&#xff0c;内存的访问速度远低于…

【信管12.2】知识管理与知识产权

知识管理与知识产权想必你对知识的概念多少都会有一些自己的理解&#xff0c;毕竟我们经过了那么多年的教育&#xff0c;学来学去可不都学习的是“知识”嘛。在今天的学习中&#xff0c;内容还是会比较多&#xff0c;因为除了知识管理相关的内容之外&#xff0c;还有知识产权相…

Matlab 最小二乘法拟合平面(SVD)

文章目录 一、简介1.1最小二乘法拟合平面1.2 SVD角度二、实现代码三、实现效果参考资料一、简介 1.1最小二乘法拟合平面 之前我们使用过最为经典的方式对平面进行了最小二乘拟合(点云最小二乘法拟合平面),其推导过程如下所示: 仔细观察一下可以发现

IP协议

网络层的一个重要作用就是把世界上的地址能够以一定的规范定义出来。地址管理路由选择网络层的代表:IP协议4位版本指的是&#xff1a;此处的取值只有两个ipv4,ipv64位首部长度&#xff1a;描述了ip报头有多长&#xff08;ip报头是变长的&#xff09;报头中有一个选项部分&#…