linux网络设备驱动(一)

2023-05-16

一、框架

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

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

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

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

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

发送大致流程:

Linux 内核中,用 sk_buff(skb)来描述一个缓存,所谓分配缓存空间,就是建立一定数量的 sk_buff。sk_buff 是 Linux 内核网络协议栈实现中最重要的结构体,它是网络数据报文在内核中的表现形式。用户态应用程序(应用层)可以通过系统调用接口访问 BSD Socket 层,传递给 Socket 的数据首先会保存在 sk_buff 对应的缓冲区中,sk_buff 的结构定义在 include/linux/skbuff.h 文件中。它保存数据报文的结构为一个双向链表,如下所示:

在这里插入图片描述

数据被储存到了 sk_buff 缓存区中,网卡驱动的发送函数 hard_start_xmit 也随之被调用,流程图如下所示:

在这里插入图片描述

  1. 首先创建一个 Socket,然后调用 write() 之类的写函数通过 Socket 访问网卡驱动,同时将数据保存在 sk_buff 缓冲区。
  2. Socket 调用发送函数 hard_start_xmit。hard_start_xmit 函数在初始化过程中会被挂接成类似于 xx_tx 的某个具体的发送函数,xx_tx 主要实现如下步骤:
    • 从 Tx BD 表中取出一个空闲的 BD。
    • 根据 sk_buff 中保存的数据修改 BD 的属性,一个是数据长度,另一个是数据报文缓存指针。值得注意的是,数据报文缓存指针对应的必须是物理地址,这是因为 DMA 在获取 BD 中对应的数据时只能识别物理地址。
    • 修改该 BD 的状态为就绪态,DMA 模块将自动发送处于就绪态 BD 中所对应的数据。
    • 移动发送 BD 表的指针指向下一个 BD。
  3. DMA 开始将处于就绪态 BD 缓存内的数据发送至网络,当发送完成后自动恢复该 BD 为空闲态。

二、重要的数据结构

1、net_device

include/linux/netdevice.h中定义了net_device结构体,他是网络设备驱动程序中最重要的结构。

该结构体,存储着网络设备的所有信息,每个网络设备都有这种结构。所有设备的net_device结构放在一个全局变量dev_base所有全局列表中。结构体中有一个next指针,用来连接系统中所有网络设备。内核把这些连接起来的设备组成一个链表,并由全局变量dev_base指向链表的第一个元素。

每个网络设备都会有一个对应的实例,然后调用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;
    /*
     *    I/O specific fields
     *    FIXME: Merge these and struct ifmap into one
     */
    /*
        描述设备所用的共享内存,用于设备与内核沟通
        其初始化和访问只会在设备驱动程序内进行
    */
    unsigned long        mem_end;
    unsigned long        mem_start;

    /* 设备自有内存映射到I/O内存的起始地址 */
    unsigned long        base_addr;

    /*
        设备与内核对话的中断编号,此值可由多个设备共享
        驱动程序使用request_irq函数分配此变量,使用free_irq予以释放
    */
    int            irq;

    /* 侦测网络状态的改变次数 */
    atomic_t        carrier_changes;

    /*
     *    Some hardware also needs these fields (state,dev_list,
     *    napi_list,unreg_list,close_list) but they are not
     *    part of the usual set specified in Space.c.
     */

    /*
        网络队列子系统使用的一组标识
        由__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;
};

header_ops

Struct header_ops包含以一系列函数指针,主要是对链路层协议头的操作,比如协议头的创建、解析、重建协议头。

struct header_ops {
    /*协议头的创建函数指针*/
	int	(*create) (struct sk_buff *skb, struct net_device *dev,
			   unsigned short type, const void *daddr,
			   const void *saddr, unsigned len);
    /*协议头解析函数指针*/
	int	(*parse)(const struct sk_buff *skb, unsigned char *haddr);		
    /*协议头重构函数指针*/
	int	(*rebuild)(struct sk_buff *skb);					
	int	(*cache)(const struct neighbour *neigh, struct hh_cache *hh);
	void	(*cache_update)(struct hh_cache *hh,
				const struct net_device *dev,
				const unsigned char *haddr);
};

net_device_ops

网卡操作函数,如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 资源。
/*
 * 网络设备打开和释放函数模板
 */
static int xxx_open(struct net_device *dev)
{
    /* 申请端口、IRQ等,类似于fops->open */
    ret = request_irq(dev->irq, &xxx_interrupt, 0, dev->name, dev);
    ···
    netif_start_queue(dev);
    ···
}


static int xxx_release(struct net_device *dev)
{
    /* 释放端口、IRQ 等,类似于fops->close */
    free_irq(dev->irq, dev);
    ···
    netif_stop_queue(dev);
    ···                     
}

ndo_start_xmit函数会启动数据包的发送,当系统调用驱动程序的xmit函数时,需要向其传入一个sk_buff结构体指针,以使得驱动程序能从上层传递下来的数据包。

*_tx

struct netdev_queue *_tx ____cacheline_aligned_in_smp;

____cacheline_aligned_in_smp是一个宏定义,参见:

linux网络源码分析(1) - TIANCJ - 博客园

____cacheline_aligned和____cacheline_aligned_in_smp_傲世阿龍的博客-CSDN博客_____cacheline_aligned

网络协议栈把数据包放入设备的队列后调用网络设备驱动程序的函数hard_start_xmit来通知网络设备数据包已经准备好了可以发送了。一个网络设备可能有多个发送队列,根据队列优先级的不同调度不同的队列,由struct netdev_queue来管理队列,*_tx指向struct netdev_queue数组的首地址,
 

struct netdev_queue {
/*
 * read-mostly part
 */
	struct net_device	*dev;//队列所属的网络设备
	netdevice_tracker	dev_tracker;

	struct Qdisc __rcu	*qdisc;//队列操作函数
	struct Qdisc		*qdisc_sleeping;

	unsigned long		tx_maxrate;
	/*
	 * Number of TX timeouts for this queue
	 * (/sys/class/net/DEV/Q/trans_timeout)
	 */
	atomic_long_t		trans_timeout;

 /*
 * write-mostly part
 */
	spinlock_t		_xmit_lock ____cacheline_aligned_in_smp;
	int			xmit_lock_owner;
	/*
	 * Time (in jiffies) of last Tx
	 */
	unsigned long		trans_start;

	unsigned long		state;//队列状态

} ____cacheline_aligned_in_smp;

2、sk_buff

ref:

理解Linux内部网络实现之关键数据结构 sk_buff – Yang Blog

网卡适配器收发数据帧流程 - 云物互联 - 博客园

netdevice.h - include/linux/netdevice.h - Linux source code (v3.3) - Bootlin

Linux网络设备驱动专题_火锅娃的博客-CSDN博客_网络设备驱动

网络设备驱动介绍(浅析)_小嵌同学的博客-CSDN博客_网络设备驱动

网络设备之net_device结构与操作 - AlexAlex - 博客园

网络设备结构体net_device介绍_TCH_world的博客-CSDN博客_net_device结构体

net_device 结构详情_wilber的技术博客_51CTO博客

https://www.csdn.net/tags/NtDaMg0sNTI2NzctYmxvZwO0O0OO0O0O.html

linux 内核协议栈 网络设备抽象 net_device_老王不让用的博客-CSDN博客

linux网络子系统分析(三)—— 设备无关层_whenloce的博客-CSDN博客_netdev_pick_tx

内核net_device设备框架的一个缺陷 - 云+社区 - 腾讯云

Linux内核中的struct net_device的dev_addr和perm_addr之间有什么区别 - VoidCC

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

linux网络设备驱动(一) 的相关文章

  • 12、TX2(ARM架构)平台换源

    关于换源的教程可参考一下其他博主的两篇文章 ARM架构换源 Ubuntu 国内源介绍 针对本机的换源操作如下 xff1a 进入配置目录 span class token function cd span etc apt 备份sources
  • VirtualBox 每天自动创建快照

    需求很简单 每天自动对虚拟机创建一个快照 避免忘记备份 同时给自己减少一点工作量 主要思路就是通过VBoxManage的命令行操作和windows的任务计划程序来完成定时备份的工作 VBoxManage 使用帮助如下 C Program F
  • c51单片机学习笔记-动态数码管实验(un)

    目的 xff1a 控制动态数码管从左至右显示数字 0 7 编译软件 xff1a keil5 过程 1 xff09 首先将 51 单片机的头文件包含进来 xff0c 然后定义 38 译码器的控制引脚 xff0c 并将共阴数码管 0 F 断码数
  • 在py-faster-rcnn/lib里make时报错: unrecognized command line option ‘-Wdate-time’

    在py faster rcnn lib里make时报错 xff1a c 43 43 pthread shared Wl O1 Wl Bsymbolic functions Wl Bsymbolic functions Wl z relro
  • C/C++ 日常学习总结(第十九篇)多线程详解

    这些讲解多线程文章都是非常好的 xff0c 我这边就归结出一个 lt 多线程详解 gt 出来 xff0c 感谢各位原创作者的辛苦劳动 xff0c 这些收藏起来方便自己消化 1 多线程笔试面试题汇总 解答地址 xff1a 概念问答 2 深入分
  • python3 算法题:七进制加法

    题目 xff1a 要求键盘输入两个七进制 0 6 数 xff0c 以空格分开 xff0c 计算两者之和输出 xff0c 例如 xff1a 输入 xff1a 16 1 输出 xff1a 20 思路 xff1a 这个题目跟十进制加法一样 xff
  • python3 实现麻将胡牌问题

    题目描述 xff1a 清一色是麻将番种之一 xff0c 指由一种花色的序数牌组成的和牌 数字1 9 xff0c 每个数字最多有4张牌 我们不考虑具体花色 xff0c 我们只看数字组合 刻子 xff1a 三张一样的牌 xff1b 如 111
  • python3爬虫简单介绍

    本文是为了防止自己以后忘了 xff0c 小白可以参考 xff0c 大神请绕道 先来扫盲 xff0c 什么是爬虫 xff1a 爬虫就是一系列按照某种规则自动从网上爬取信息的代码或者脚本 本文代码功能 xff1a 从百度百科里面爬取20个和py
  • python3 使用urllib.request.urlopen及re.findall爬取网页图片并保持本地

    本例使用urllib及re正则表达式 xff0c 爬取网页上 xff08 王俊凯百度百科 xff09 所有以jpg结尾的图片 xff0c 并保存本地 import re from urllib span class token punctu
  • python3 爬取网页内容解析并存入MySQL数据库

    爬取网页内容解析并存入MySQL数据库 用到的第三方库 xff1a BeautifulSoup xff1a 解析网页内容 xff0c 建议安装方法 xff1a pip install beautifulsoup4 pymysql xff1a
  • python二维列表按照某列(字符串列)排序;忽略大小写+区分大小写

    python二维列表按照某列 xff08 字符串列 xff09 排序 xff1b 忽略大小写 43 区分大小写 使用list自带的sorted 方法 xff0c data 61 sorted data key 61 lambda x x 1
  • tkinter 出现两个窗口 tk(未响应) 解决方法

    问题 xff1a tkinter界面开发 xff0c 莫名出现一个叫 tk 未响应 的小窗口 xff0c 最后发现是因为自定义了窗口图标导致产生多余窗口 解决方法 xff1a 将设置窗口图标代码放到设置窗口大小代码之后即可 xff08 该方
  • python3适配pykml教程

    pykml是用python2写的 xff0c 由于python3和python2语法及函数名有所不同 xff0c python3使用的时候需要手动修改几个地方 xff0c 如下 xff1a 1 出现 xff1a ModuleNotFound
  • c51单片机学习笔记-独立按键实验

    目的 xff1a 通过开发板上的独立按键 K1 控制 D1 指示灯亮灭 编译软件 xff1a keil5 过程 xff1a xff08 1 xff09 定义独立按键控制脚 sbit KEY1 61 P3 1 sbit KEY2 61 P3
  • openpyxl为指定区域设置边框为粗匣框线

    前言 xff1a 最近在用openpyxl分析Excel数据 xff0c 为了让表格层次更分明 xff0c 想给制定区域添加粗匣框线 xff0c 网上没有找到现成的方法 xff0c 自己摸索了一下 xff0c 终于解决了 xff0c 现在记
  • ubuntu上网问题以及ping通网络设备

    问题一 xff1a ubuntu上网问题 如何ping www baidu com Ubuntu上网模式有两种 xff1a 桥接和NAT 1 桥接模式 xff1a 前提是 xff1a 主机是连接的无线网 xff0c 主机有线网卡的IP设置的
  • Python脚本调用C++动态库,C++调用Python脚本实操

    一 Python调用C 43 43 动态库 实现方法 xff1a 使用python 的ctypes 模块加载dll 首先 xff0c 需要用VS创建一个dll动态库 xff0c 网上方法很多 xff0c 就不细说了 xff0c 代码如下 x
  • 利用GPU训练时的常见错误

    1 CUDA VIDIBLE DEVICES 61 4 5 python3 main py 我想在集群条件下利用4 5号GPU xff0c 由于模型较小 xff0c 并不清楚是都可以指定4 5号GPU xff08 内存占用情况看不出来 后续
  • Jetson TX1底板的接口调试

    1 I2C总线上外设查询 I2C Tools的安装和使用 在控制台输入 sudo apt get install i2c tools 安装完成后可以使用命令验证安装成功 sudo i2cdetect l I2C设备查询使用 sudo i2c
  • 驱动——platform驱动总线三种匹配方式

    三种platform驱动匹配方式代码案例以及现象 方式一 xff1a 通过设置名字进行匹配 相关API简介 xff1a 1 platform device的API 分配对象 struct platform device const char

随机推荐

  • 开源框架APM工具--SkyWalking原理与应用

    一 分布式链路追踪简介 随着业务系统的不断发展 微服务架构的演进 xff0c 从原来的单体应用架构 垂直应用架构 分布式 SOA 架构到现在的微服务架构 xff0c 系统逐步走向微服务化以适应用户高并发请求等需求 在微服务架构中 xff0c
  • 什么是弹性云服务器?

    ecs云服务器是由CPU 内存 镜像 云硬盘组成的一种可随时获取 弹性可扩展的计算服务器 xff0c 同时它结合虚拟私有云 虚拟防火墙 数据多副本保存等能力 xff0c 为您打造一个高效 可靠 安全的计算环境 xff0c 确保您的服务持久稳
  • linux下修改MAC地址的问题解决

    在linux中 xff0c 修改MAC地址 ifdown eth0 ifconfig eth0 hw ether 12 xff1a 34 xff1a 56 xff1a 78 xff1a 90 xff1a 12 xff08 修改的MAC地址跟
  • 51串口发送数据的格式

    串行口控制寄存器SCON SCON的字节地址是98H xff0c 其格式如下 xff1a SM0 SM1 xff1a 串行口工作方式控制位 xff1a SM0 SM1 工作方式 功能 波特率 00 方式0 同步移位寄存器 fosc 12 0
  • c51单片机学习笔记-矩阵按键实验

    目的 xff1a 通过数码管显示矩阵按键 S1 S16 按下后键值 0 F 编译软件 xff1a keil5 过程 xff1a xff08 1 xff09 定义各端口 include 34 reg52 h 34 typedef unsign
  • CMake 添加第三方库的几种依赖方式

    转载链接 xff1a C 43 43 工程 xff1a 总结 CMake 添加第三方库依赖方式git submodule find library FetchContent CPM等 github地址 cpp cmake example 第
  • vue.js中v-for的使用及索引获取

    vue js中v for的使用及索引获取 1 v for 直接上代码 示例一 xff1a lt DOCTYPE html gt lt html gt lt head gt lt meta charset 61 34 utf 8 34 gt
  • (转贴)Windows CE 5.0下串口驱动硬件FIFO控制Bug分析及修正方法

    转贴自 xff1a 驱动开发网 原贴地址 xff1a http bbs driverdevelop com read php tid 61 109193 amp fpage 61 0 amp toread 61 amp page 61 1
  • 四剑客和正则表达式常见故障及困惑集合(待更新)

    一 find命令 warning警告 maxdepth 这个参数要放在其他参数之前 root 64 oldboyedu59 find type d maxdepth 1 find warning you have specified the
  • sed的使用

    一 xff0c 替换文本 s pattern replacement flags replacement会替换pattern 例如 xff1a root 64 node1 sed cat data2 txt This is a test o
  • KVM虚拟化-创建-桥接-硬盘-快照

    1 创建 使用virt manager进行创建 virt manager进入管理器 点击如图进行创建 将ISO下载到虚拟机里面 点击浏览 下面是虚拟机名字 选择本地浏览 选中CentOS的iso 选择后前进 选择内存和cpu xff0c 前
  • 串口专题(一)——基础知识

    前言 xff1a 为了方便查看博客 xff0c 特意申请了一个公众号 xff0c 附上二维码 xff0c 有兴趣的朋友可以关注 xff0c 和我一起讨论学习 xff0c 一起享受技术 xff0c 一起成长 1 概念介绍 串行口是计算机一种常
  • STM32中晶振的原理与作用

    前言 xff1a 为了方便查看博客 xff0c 特意申请了一个公众号 xff0c 附上二维码 xff0c 有兴趣的朋友可以关注 xff0c 和我一起讨论学习 xff0c 一起享受技术 xff0c 一起成长 转载地址 STM32中晶振的原理与
  • STM32学习笔记一一UCOSII(1)

    前言 xff1a 为了方便查看博客 xff0c 特意申请了一个公众号 xff0c 附上二维码 xff0c 有兴趣的朋友可以关注 xff0c 和我一起讨论学习 xff0c 一起享受技术 xff0c 一起成长 1 简介 UCOSII 是一个可以
  • PADS 原理图库文件绘制

    前言 xff1a 为了方便查看博客 xff0c 特意申请了一个公众号 xff0c 附上二维码 xff0c 有兴趣的朋友可以关注 xff0c 和我一起讨论学习 xff0c 一起享受技术 xff0c 一起成长 1 PADS Logic 参数设置
  • prometheus监管平台(一)(开源)

    prometheus监管平台 xff08 一 xff09 xff08 开源 xff09 一 登录二 首页三 General Management功能四 Host Management功能五 Job Management功能六 Alarm M
  • vncserver连接后窗口显示太小

    VNC server的默认的分辨率是1024x768 如果要改变VNC server的分辨率 1 可以用一下命令启动VNC server root 64 localhost vncserver geometry 1280x1024 这种修改
  • dfs (二进制枚举,暴力,马的管辖)

    在中国象棋中 xff0c 马是走日字的 一个马的管辖范围指的是当前位置以及一步之内能走到的位置 xff0c 下图的绿色旗子表示马能走到的位置 如果一匹马的某个方向被蹩马脚 xff0c 它就不能往这个方向跳了 xff0c 如下图所示 xff0
  • linux进程(四)——进程的几种状态

    usr src linux headers 4 15 0 45 include linux Used in tsk gt state define TASK RUNNING 0x0000 define TASK INTERRUPTIBLE
  • linux网络设备驱动(一)

    一 框架 1 xff09 网络协议接口层 向网络层协议提供统一的数据包收发接口 xff0c 不论上层协议是ARP xff0c 还是IP xff0c 都通过dev queue xmit 函数发送数据 xff0c 并通过netif rx 函数接