深入理解Linux网络随笔(一):内核是如何接收网络包的(上篇)
深入理解Linux网络随笔(一):内核是如何接收网络包的(上篇)
1、TCP/IP模型概述
从Linux视角看,TCP/IP网络分层模型包括用户空间和内核空间。用户空间(应用层)负责HTTP、FTP等协议的网络服务。内核空间则实现了各个协议层:
- 传输层:TCP确保可靠传输,UDP提供无连接快速传输。
- 网络层:IP负责数据包路由,ICMP用于网络诊断。
- 链路层:通过网络设备驱动处理数据帧和硬件交互。
- 物理层:网卡实现物理信号收发。
各层通过封装与解封装协作完成数据传输,内核通过socket接口支持用户进程与网络交互。
2、内核收包过程
内核收包路径如下图所示,其核心步骤小结如下:
1、网卡NIC接收到网络数据包
由于网卡位于物理层,此时接收的数据以电信号形式存在,网卡将电信号转换为数字信号,并进行数据帧的封装和预处理。
2、以DMA方式将数据帧写放入内存
采用直接内存访问(DMA)技术,将数据帧直接写入内核中预定的缓冲区,减少CPU负担并提高数据传输效率。
3、网卡触发硬中断通知CPU
4、软中断处理
CPU收到中断请求,调用网络设备驱动注册的中断处理函数,将中断请求转为软中断,提交给软中断处理机制。硬中断的目的是尽快响应硬件,而软中断则允许系统进行更复杂的处理。
5、ksoftirqd内核线程处理,poll轮询收包
- 软中断请求由ksoftirqd内核线程处理,通过poll轮询的方式处理所有网络相关的软中断任务。批量处理多个网络数据包,减少中断上下文切换的开销。
- 网卡的接收缓冲区(Ring Buffer)中取出数据,将其封装为Socket缓冲区(skb)对象。
skb
是Linux内核中用于描述网络数据包的数据结构。
6、协议栈处理网络帧
- 协议栈开始处理网路帧,处理完成的data存于socket的接收队列(每个进程通过socket与内核网络栈通信,接收到的数据会被放入该进程对应的接收队列)。
- socket充当用户进程和内核通信桥梁
7、内核唤醒用户进程
- 调用如
recv()
或read()
等系统调用读取数据,数据会从接收队列中取出并交给用户空间。
2.1Linux启动
2.1.1 创建ksoftirqd内核线程
ksoftirqd
是一种 per-CPU 内核线程,意味着每个 CPU 核心都会有一个独立的 ksoftirqd
线程来处理该核心的软中断。在 Linux 内核中,ksoftirqd
的优先级相对较低。当系统中有更高优先级的任务(如硬中断、实时任务或其他重要进程)需要处理时,ksoftirqd
线程会被调度器推迟执行,等待 CPU 资源空闲。只有当 CPU 处于空闲状态,或者软中断的处理已经无法继续推迟时,ksoftirqd
线程才会被调度执行。这种延迟处理机制,使得ksoftirqd
只会在 CPU 空闲或者软中断处理不能再推迟时才会被调度执行,最大化 CPU 的利用率,避免不必要的资源浪费。
ps
命令查看**ksoftirq内核线程, **ps -eLf | grep ksoftirqd
命令查看到了 [ksoftirqd/0]
、[ksoftirqd/1]
、[ksoftirqd/2]
、[ksoftirqd/3]
这 4 个 ksoftirq
内核线程,使用 nproc
命令查看到当前机器的 CPU 核心数为 4 。ksoftirqd线程数量等于机器的CPU核心数。
Linux内核启动过程中,系统初始化的时候在kernel/smpboot.c中调用了smpboot_register_percpu_thread
为每个CPU核心启动一个内核线程,该函数会进一步执行到spawn_ksoftirqd(位于kernel/ksoftirqd.c)来创建softirqd线程。
//kernel/softirq.c
static __init int spawn_ksoftirqd(void)
{cpuhp_setup_state_nocalls(CPUHP_SOFTIRQ_DEAD, "softirq:dead", NULL,takeover_tasklets);//注册CPU的热插拔状态,确保在CPU下线时能够正确处理软中断BUG_ON(smpboot_register_percpu_thread(&softirq_threads));//负责在每一个CPU上注册并启动软中断线程softirqdreturn 0;
}
early_initcall(spawn_ksoftirqd);
spawn_ksoftirqd
会在内核启动时创建并初始化每个CPU上的软中断线程,并为每个CPU设置适当的热插拔状态。通过这种方式,系统可以在多核环境下并行处理软中断。
static struct smp_hotplug_thread softirq_threads = {.store = &ksoftirqd,.thread_should_run = ksoftirqd_should_run,.thread_fn = run_ksoftirqd,.thread_comm = "ksoftirqd/%u",
};
smp_hotplug_thread
结构体描述热插拔线程(hotplug thread),即在系统中随着 CPU 的启停而创建或销毁的线程。softirq_threads
专门用来描述软中断线程,设置回调函数ksoftirqd_should_run
,决定线程是否需要继续执行;设置回调函数run_ksoftirqd
处理软中断任务。(软中断核心流程不做解释)
// include/linux/interrupt.h
enum
{HI_SOFTIRQ = 0, // 高优先级软中断,通常用于处理紧急任务TIMER_SOFTIRQ, // 定时器软中断,处理内核定时器相关的任务NET_TX_SOFTIRQ, // 网络传输发送软中断,用于处理网络发送操作NET_RX_SOFTIRQ, // 网络传输接收软中断,用于处理网络接收操作BLOCK_SOFTIRQ, // 块设备软中断,处理与块设备(如硬盘)相关的任务BLOCK_IOPOLL_SOFTIRQ, // 块 I/O 轮询软中断,负责检查 I/O 操作是否完成TASKLET_SOFTIRQ, // tasklet 软中断,处理延迟任务SCHED_SOFTIRQ, // 调度软中断,处理任务调度相关的任务HRTIMER_SOFTIRQ, // 高分辨率定时器软中断,处理高精度定时器任务RCPU_SOFTIRQ, // RCPU 同步软中断,涉及到 RCPU 的更新和回调处理NR_SOFTIRQS // 软中断的总数,表示系统中所有软中断类型的数量
};
软中断类型中,网络传输发送软中断NET_TX_SOFTIRQ
,网络传输接收软中断NET_RX_SOFTIRQ
。
2.1.2网络子系统初始化
Linux内核通过调用subsys_initcall
来初始化各个子系统,使用subsys_initcall(net_dev_init)
初始化网络设备。
static int __init net_dev_init(void)
{
....../** Initialise the packet receive queues.*/// *初始化每个 CPU 上的网络接收队列和软中断相关的数据结构。for_each_possible_cpu(i) {struct work_struct *flush = per_cpu_ptr(&flush_works, i);struct softnet_data *sd = &per_cpu(softnet_data, i);INIT_WORK(flush, flush_backlog);skb_queue_head_init(&sd->input_pkt_queue);//输入数据包队列skb_queue_head_init(&sd->process_queue);//处理队列
......init_gro_hash(&sd->backlog);//哈希表sd->backlog.poll = process_backlog;//回调sd->backlog.weight = weight_p;//Gro权值}//初始化阶段结束dev_boot_phase = 0;/* The loopback device is special if any other network devices* is present in a network namespace the loopback device must* be present. Since we now dynamically allocate and free the* loopback device ensure this invariant is maintained by* keeping the loopback device as the first device on the* list of network devices. Ensuring the loopback devices* is the first device that appears and the last network device* that disappears.*///注册回环设备if (register_pernet_device(&loopback_net_ops))goto out;//注册默认网路设备if (register_pernet_device(&default_device_ops))goto out;//启动网络传输发送软中断open_softirq(NET_TX_SOFTIRQ, net_tx_action);//启动网络传输接收软中断open_softirq(NET_RX_SOFTIRQ, net_rx_action);// 设置 CPU 热插拔状态,注册 CPU 下线时的清理函数rc = cpuhp_setup_state_nocalls(CPUHP_NET_DEV_DEAD, "net/dev:dead",NULL, dev_cpu_dead);WARN_ON(rc < 0);rc = 0;
out:return rc;
}
网络子系统初始化过程,为每个CPU初始化softnet_data
结构体,进行软中断处理和管理网络数据包队列,为软中断注册处理函数使用方法open_softirq
,网络传输发送软中断NET_TX_SOFTIRQ
处理注册回调处理函数net_tx_action
,网络传输接收软中断NET_RX_SOFTIRQ
处理注册回调处理函数net_rx_action
。
struct softnet_data {struct list_head poll_list;struct sk_buff_head process_queue;/* stats */unsigned int processed;unsigned int time_squeeze;
#ifdef CONFIG_RPSstruct softnet_data *rps_ipi_list;
#endif
#ifdef CONFIG_NET_FLOW_LIMITstruct sd_flow_limit __rcu *flow_limit;
#endifstruct Qdisc *output_queue;struct Qdisc **output_queue_tailp;struct sk_buff *completion_queue;
#ifdef CONFIG_XFRM_OFFLOADstruct sk_buff_head xfrm_backlog;
#endif/* written and read only by owning cpu: */struct {u16 recursion;u8 more;
#ifdef CONFIG_NET_EGRESSu8 skip_txqueue;
#endif} xmit;
#ifdef CONFIG_RPS/* input_queue_head should be written by cpu owning this struct,* and only read by other cpus. Worth using a cache line.*/unsigned int input_queue_head ____cacheline_aligned_in_smp;/* Elements below can be accessed between CPUs for RPS/RFS */call_single_data_t csd ____cacheline_aligned_in_smp;struct softnet_data *rps_ipi_next;unsigned int cpu;unsigned int input_queue_tail;
#endifunsigned int received_rps;unsigned int dropped;struct sk_buff_head input_pkt_queue;struct napi_struct backlog;/* Another possibly contended cache line */spinlock_t defer_lock ____cacheline_aligned_in_smp;int defer_count;int defer_ipi_scheduled;struct sk_buff *defer_list;call_single_data_t defer_csd;
};
在每个 softnet_data
结构体中,poll_list
用来链接需要轮询的网络设备接口。每个 CPU 上的 softnet_data
结构体都有一个 poll_list
,记录了当前需要处理的网络设备。这样可以通过轮询这些设备的接口来处理网络数据包。
在 Linux 网络栈的工作流程中,NAPI 会定期轮询设备(而不是每次包都中断),有效地减少中断处理的负载。每个网络设备的 NAPI 结构体都会被放入这个链表中,表示这个设备正在进行轮询,等待数据包的处理。
void open_softirq(int nr, void (*action)(struct softirq_action *))
{softirq_vec[nr].action = action;
}
软中断处理函数绑定软中断号通过softirq_vec
数组实现,每一个元素对应一种软中断类型。
2.1.3协议栈注册
Linux内核实现了网络层的IP协议,同样也实现了TCP、UDP协议,协议栈初始化入口函数为fs_initcall(inet_init)
,调用inet_init
进行网络协议栈注册。
static int __init inet_init(void)
{......if (inet_add_protocol(&icmp_protocol, IPPROTO_ICMP) < 0)pr_crit("%s: Cannot add ICMP protocol\n", __func__);if (inet_add_protocol(&udp_protocol, IPPROTO_UDP) < 0)pr_crit("%s: Cannot add UDP protocol\n", __func__);if (inet_add_protocol(&tcp_protocol, IPPROTO_TCP) < 0)pr_crit("%s: Cannot add TCP protocol\n", __func__); ......dev_add_pack(&ip_packet_type);
}
使用inet_add_protocol
向协议栈注册协议,协议定义结构体如下:
static struct packet_type ip_packet_type __read_mostly = {.type = cpu_to_be16(ETH_P_IP),.func = ip_rcv,.list_func = ip_list_rcv,
};
static const struct net_protocol icmp_protocol = {.handler = icmp_rcv,.err_handler = icmp_err,.no_policy = 1,
};
static const struct net_protocol udp_protocol = {.handler = udp_rcv,.err_handler = udp_err,.no_policy = 1,
};
static const struct net_protocol tcp_protocol = {.handler = tcp_v4_rcv,//回调处理函数.err_handler = tcp_v4_err,.no_policy = 1,.icmp_strict_tag_validation = 1,
};
dev_add_pack负责将新的packet_type
结构体添加于协议类型链表。
void dev_add_pack(struct packet_type *pt)
{struct list_head *head = ptype_head(pt);// 获取对应协议类型的链表头spin_lock(&ptype_lock);list_add_rcu(&pt->list, head);// 将新的 packet_type 结构体添加到链表中spin_unlock(&ptype_lock);
}
ptype_head
是一个内联函数,根据传入的 packet_type
结构体 (pt
) 获取对应协议类型的链表头。这个链表存储了与该协议类型相关的处理程序。它根据协议类型和设备信息决定返回哪个链表的头部。
static inline struct list_head *ptype_head(const struct packet_type *pt)
{if (pt->type == htons(ETH_P_ALL)) // 如果协议类型是 ETH_P_ALLreturn pt->dev ? &pt->dev->ptype_all : &ptype_all; // 返回设备特定的链表或全局链表else // 如果协议类型不是 ETH_P_ALLreturn pt->dev ? &pt->dev->ptype_specific : &ptype_base[ntohs(pt->type) & PTYPE_HASH_MASK]; // 返回设备特定的链表或根据协议类型哈希的链表
}
协议类型通过 ntohs(pt->type) & PTYPE_HASH_MASK
进行哈希计算,决定将其对应的 packet_type
结构体插入到 ptype_base
数组中的哪个位置,在这里IP协议会注册到ptype_base
哈希表,存储ip_rcv
函数处理地址。
int inet_add_protocol(const struct net_protocol *prot, unsigned char protocol)
{return !cmpxchg((const struct net_protocol **)&inet_protos[protocol],NULL, prot) ? 0 : -1;
}
EXPORT_SYMBOL(inet_add_protocol);
TCP、UDP、ICMP协议注册方式与IP协议不同,通过inet_add_protocol
函数调用完成协议注册,将协议类型protocol
对应的处理程序添加于inet_protos
数组。
2.1.4网卡驱动初始化
每一个驱动程序(不仅仅包括网卡驱动程序)会使用module_init向内核注册一个初始化函数,当驱动程序被加载时,内核会调用这个函数,以igb网卡驱动程序为例,其初始化函数如下。
static int __init igb_init_module(void)
{
......ret = pci_register_driver(&igb_driver);return ret;
}
module_init(igb_init_module);
//驱动相关信息
static struct pci_driver igb_driver = {.name = igb_driver_name,.id_table = igb_pci_tbl,.probe = igb_probe,.remove = igb_remove,
#ifdef CONFIG_PM.driver.pm = &igb_pm_ops,
#endif.shutdown = igb_shutdown,.sriov_configure = igb_pci_sriov_configure,.err_handler = &igb_err_handler
};
注册PCI驱动程序在pci_register_driver
函数完成,函数调用关系pci_register_driver
–>__pci_register_driver
。
int __pci_register_driver(struct pci_driver *drv, struct module *owner,const char *mod_name)
{/* initialize common driver fields */drv->driver.name = drv->name; // 驱动名称drv->driver.bus = &pci_bus_type; // 绑定到 PCI 总线类型drv->driver.owner = owner; // 驱动模块所有者drv->driver.mod_name = mod_name; // 模块名称drv->driver.groups = drv->groups; // 驱动的分组(若有)drv->driver.dev_groups = drv->dev_groups; // 设备的分组(若有)spin_lock_init(&drv->dynids.lock); // 初始化锁,用于动态分配的设备 IDINIT_LIST_HEAD(&drv->dynids.list); // 初始化动态设备列表/* register with core */return driver_register(&drv->driver); // 注册驱动到内核的核心驱动模型中
}
EXPORT_SYMBOL(__pci_register_driver);
__pci_register_driver
调用完成后,Linux内核就会知道驱动相关信息(如igb网卡驱动名称、igb_probe地址等),当网卡设备被识别以后,Linux内核会调用.probe方法(igb_probe方法)。
static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{......//获取MAC地址if (eth_platform_get_mac_address(&pdev->dev, hw->mac.addr)) {/* copy the MAC address out of the NVM */if (hw->mac.ops.read_mac_addr(hw))dev_err(&pdev->dev, "NVM Read Error\n");}//DMA初始化err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));//注册ethtool函数igb_set_ethtool_ops(netdev);//注册net_device_ops、netdev等netdev = alloc_etherdev_mq(sizeof(struct igb_adapter),IGB_MAX_TX_QUEUES);if (!netdev)goto err_alloc_etherdev;SET_NETDEV_DEV(netdev, &pdev->dev);pci_set_drvdata(pdev, netdev);adapter = netdev_priv(netdev);adapter->netdev = netdev;adapter->pdev = pdev;hw = &adapter->hw;hw->back = adapter;......netdev->netdev_ops = &igb_netdev_ops;// 注册NAPI相关的资源分配err = igb_alloc_q_vector(adapter);if (err)goto err_alloc_q_vector;......
}
igb_probe初始化过程中,调用igb_alloc_q_vector
–>netif_napi_add
,初始化NAPI机制,对于igb网卡来说,NAPI机制的poll函数是igb_poll
。
static int igb_alloc_q_vector(struct igb_adapter *adapter,int v_count, int v_idx,int txr_count, int txr_idx,int rxr_count, int rxr_idx)
{..../* initialize NAPI */netif_napi_add(adapter->netdev, &q_vector->napi, igb_poll);....
}
2.1.5启动网卡
static const struct net_device_ops igb_netdev_ops = {.ndo_open = igb_open,.ndo_stop = igb_close,.ndo_start_xmit = igb_xmit_frame,.ndo_get_stats64 = igb_get_stats64,.ndo_set_rx_mode = igb_set_rx_mode,.ndo_set_mac_address = igb_set_mac,.ndo_change_mtu = igb_change_mtu,.ndo_eth_ioctl = igb_ioctl,.ndo_tx_timeout = igb_tx_timeout,.ndo_validate_addr = eth_validate_addr,.ndo_vlan_rx_add_vid = igb_vlan_rx_add_vid,.ndo_vlan_rx_kill_vid = igb_vlan_rx_kill_vid,.ndo_set_vf_mac = igb_ndo_set_vf_mac,.ndo_set_vf_vlan = igb_ndo_set_vf_vlan,.ndo_set_vf_rate = igb_ndo_set_vf_bw,.ndo_set_vf_spoofchk = igb_ndo_set_vf_spoofchk,.ndo_set_vf_trust = igb_ndo_set_vf_trust,.ndo_get_vf_config = igb_ndo_get_vf_config,.ndo_fix_features = igb_fix_features,.ndo_set_features = igb_set_features,.ndo_fdb_add = igb_ndo_fdb_add,.ndo_features_check = igb_features_check,.ndo_setup_tc = igb_setup_tc,.ndo_bpf = igb_xdp,.ndo_xdp_xmit = igb_xdp_xmit,
};
igb_netdev_ops
结构体定义了网络设备常见的执行操作,当网卡被启动时调用回调函数igb_open
。函数调用关系igb_open
–>_igb_open
。
static int __igb_open(struct net_device *netdev, bool resuming)
{......netif_carrier_off(netdev);/* allocate transmit descriptors */err = igb_setup_all_tx_resources(adapter);if (err)goto err_setup_tx;/* allocate receive descriptors */err = igb_setup_all_rx_resources(adapter);if (err)goto err_setup_rx;err = igb_request_irq(adapter);if (err)goto err_req_irq;......igb_irq_enable(adapter);for (i = 0; i < adapter->num_q_vectors; i++)napi_enable(&(adapter->q_vector[i]->napi));......}
__igb_open
中调用igb_setup_all_tx_resources
分配TX队列内存,调用igb_setup_all_rx_resources
分配RX队列内存,调用igb_request_irq
注册中断处理函数,igb_irq_enable
启用硬中断, napi_enable
启用NAPI机制。
static int igb_setup_all_rx_resources(struct igb_adapter *adapter)
{struct pci_dev *pdev = adapter->pdev;int i, err = 0;for (i = 0; i < adapter->num_rx_queues; i++) {err = igb_setup_rx_resources(adapter->rx_ring[i]);......}}return err;
}
循环创建若干个接收队列,调用igb_setup_rx_resources
为RX队分配资源,前期准备工作已完成,等待网络数据包到来~~。
int igb_setup_rx_resources(struct igb_ring *rx_ring)
{
......//申请igb_rx_buffer数组内存供内核使用size = sizeof(struct igb_rx_buffer) * rx_ring->count;rx_ring->rx_buffer_info = vmalloc(size);if (!rx_ring->rx_buffer_info)goto err;//申请e1000_adv_rx_desc数组内存供网卡使用/* Round up to nearest 4K */rx_ring->size = rx_ring->count * sizeof(union e1000_adv_rx_desc);rx_ring->size = ALIGN(rx_ring->size, 4096);rx_ring->desc = dma_alloc_coherent(dev, rx_ring->size,&rx_ring->dma, GFP_KERNEL);if (!rx_ring->desc)goto err;//初始化rx_ring->next_to_alloc = 0;rx_ring->next_to_clean = 0;rx_ring->next_to_use = 0;
......return 0;
}
相关文章:
深入理解Linux网络随笔(一):内核是如何接收网络包的(上篇)
深入理解Linux网络随笔(一):内核是如何接收网络包的(上篇) 1、TCP/IP模型概述 从Linux视角看,TCP/IP网络分层模型包括用户空间和内核空间。用户空间(应用层)负责HTTP、FTP等协议的…...
SQL-leetcode—1393. 股票的资本损益
1393. 股票的资本损益 Stocks 表: ---------------------- | Column Name | Type | ---------------------- | stock_name | varchar | | operation | enum | | operation_day | int | | price | int | ---------------------- (stock_name, operation_day) 是这张…...
热更图片方案
项目平常需要对线上一些图片资源修正,所以需要热更图片功能。 远端入口新增字段配json文件 {"1.1.22030303":{"sprite":{"assets/ui/common/images/acient_gold.png" : "https://aaaa.png","assets/ui/common/image…...
Flutter PIP 插件 ---- iOS Video Call
以下是一篇关于在 iOS 中实现画中画(PiP)功能的技术博客: iOS 画中画(PiP)功能实现指南 简介 画中画(Picture in Picture, PiP)是一项允许用户在使用其他应用时继续观看视频内容的功能。本文将详细介绍如何在 iOS 应用中实现 PiP 功能。 系统要求 iOS 15.0 及以上版本AVKi…...
本地部署DeepSeek开源大模型:从零开始的详细教程
友情提示:本文内容全部由银河易创(https://ai.eaigx.com)AI创作平台deepseek-reasoner模型生成,仅供参考。请根据具体情况和需求进行适当的调整和验证。 近年来,随着人工智能技术的飞速发展,大模型在各个领…...
java项目之基于SSM会议管理系统的设计与实现源码(ssm+mysql)
项目简介 基于SSM会议管理系统的设计与实现实现了以下功能: 基于SSM会议管理系统的设计与实现的主要使用者分为:管理员登录后修改个人的密码。用户管理中,对公司内的用户进行管理,包括会议管理员和员工,管理部门信息…...
PortSwigger——WebSockets vulnerabilities
文章目录 一、WebSockets二、Lab: Manipulating WebSocket messages to exploit vulnerabilities三、Lab: Manipulating the WebSocket handshake to exploit vulnerabilities四、Using cross-site WebSockets to exploit vulnerabilities4.1 跨站WebSocket劫持(cro…...
STM32系统架构介绍
STM32系统架构 1. CM3/4系统架构2. CM3/4系统架构-----存储器组织结构2.1 寄存器地址映射(特殊的存储器)2.2 寄存器地址计算2.3 寄存器的封装 3. CM3/4系统架构-----时钟系统 STM32 和 ARM 以及 ARM7是什么关系? ARM 是一个做芯片标准的公司,…...
智能GUI Agent是什么,有什么应用领域
智能GUI Agent是什么 研究背景与目的:GUI长期主导人机交互,LLM特别是多模态模型的出现,为GUI自动化带来变革,催生了基于LLM的GUI智能体。这些智能体可理解自然语言指令,处理复杂GUI元素并执行操作,改变了用户与软件交互方式。论文旨在梳理该领域发展脉络,剖析关键要素,…...
Python3操作MongoDB批量upsert
个人博客地址:Python3操作MongoDB批量upsert | 一张假钞的真实世界 代码如下: mongoClient MongoClient(mongodb://172.16.72.213:27017/) opsDb mongoClient.ops azScheduled opsDb.azScheduledFlowbulkOpers [] for flow in scheduledFlows.valu…...
3dgs 2025 学习笔记
CVPR 2024 3D方向总汇包含(3DGS、三维重建、深度补全、深度估计、全景定位、表面重建和特征匹配等)_cvpr2024-structure-awaresparse-viewx-ray3dreconstr-CSDN博客 https://github.com/apple/ml-hugs 3DGS COLMAP-Free 3D Gaussian Splatting ⭐code &…...
大模型笔记:pytorch实现MOE
0 导入库 import torch import torch.nn as nn import torch.nn.functional as F 1 专家模型 #一个简单的专家模型,可以是任何神经网络架构 class Expert(nn.Module):def __init__(self, input_size, output_size):super(Expert, self).__init__()self.fc nn.L…...
C#/.NET/.NET Core技术前沿周刊 | 第 25 期(2025年2.1-2.9)
前言 C#/.NET/.NET Core技术前沿周刊,你的每周技术指南针!记录、追踪C#/.NET/.NET Core领域、生态的每周最新、最实用、最有价值的技术文章、社区动态、优质项目和学习资源等。让你时刻站在技术前沿,助力技术成长与视野拓宽。 欢迎投稿、推荐…...
package.json 文件配置
创建 Node.js 的配置文件 package.json npm init -y package.json 文件配置说明 配置说明示例name指定项目的名称,必须是小写字母,可以包含字母、数字、连字符(-)或下划线(_),不能有特殊字符…...
相机模数转换
模拟图像是什么? 模拟图像是指连续变化的图像,它通常来源于现实世界的物理场景,并通过光学系统(如相机镜头)投射到感光介质上。模拟图像是连续的,这意味着它在空间和颜色值上都有无穷的细节。例如…...
mysql大数据量分页查询
一、什么是MySQL大数据量分页查? MySQL大数据量分页查是指在使用MySQL数据库时,将大量数据分成多个较小的部分进行显示,以提高查询效率和用户体验。分页查询通常用于网页或应用程序中,以便用户能够逐步浏览结果集。 二、为什…...
组织结构改革:激活企业活力的 “源头活水”
难以适应市场变化、内部沟通与协作不畅、决策效率低下、运营成本增加、人才流失严重、员工士气下降、战略目标难以实现……企业如何根据市场环境变化和自身发展需求,灵活调整组织框架,赋能企业的持续健康发展? 某国有投资建设集团旗下的二级…...
金融风控项目-1
文章目录 一. 案例背景介绍二. 代码实现1. 加载数据2. 数据处理3. 查询 三. 业务解读 一. 案例背景介绍 通过对业务数据分析了解信贷业务状况 数据集说明 从开源数据改造而来,基本反映真实业务数据销售,客服可以忽略账单周期,放款日期账单金…...
Java常用设计模式面试题总结(内容详细,简单易懂)
设计模式的分类 创建型模式:通过隐藏对象创建的细节,避免直接使用 new 关键字实例化对象,从而使程序在判断和创建对象时更具灵活性。常见的模式包括: 工厂模式抽象工厂模式单例模式建造者模式原型模式 结构型模式:通…...
【Elasticsearch】文本分析Text analysis概述
文本分析概述 文本分析使 Elasticsearch 能够执行全文搜索,搜索结果会返回所有相关的结果,而不仅仅是完全匹配的结果。 如果你搜索“Quick fox jumps”,你可能希望找到包含“A quick brown fox jumps over the lazy dog”的文档,…...
ATF系统安全从入门到精通
CSDN学院课程连接:https://edu.csdn.net/course/detail/39573...
C# 上位机--变量
C# 上位机--变量 在 C# 上位机开发领域,变量是构建程序逻辑的基础元素之一。它就像是一个容器,用于存储各种类型的数据,从简单的数值到复杂的对象。正确理解和使用变量,对于开发出高效、稳定且易于维护的上位机程序至关重要。本文…...
π 的奥秘:如何用有理数逼近无理数?
本文将围绕有理数、无理数、连续统以及它们之间的深刻联系展开讨论,并结合具体的数学理论如康托尔区间套定理、戴德金分割、柯西施瓦茨不等式等,进行简要探讨 由于本文并未深入探讨,可能存在部分不严谨的地方,也欢迎各位进行纠正…...
LeetCode --- 436周赛
题目列表 3446. 按对角线进行矩阵排序 3447. 将元素分配给有约束条件的组 3448. 统计可以被最后一个数位整除的子字符串数目 3449. 最大化游戏分数的最小值 一、按对角线进行矩阵排序 直接模拟,遍历每一个斜对角线,获取斜对角线上的数字,排…...
绘制中国平安股价的交互式 K 线图
在本文中,探索如何使用 Python 的强大库进行股市数据分析与可视化。我们将以中国平安(股票代码:sh601318)为例,展示如何获取其股票数据,并绘制一张交互式 K 线图。 K 线图是股市分析中不可或缺的工具,它能够直观地显示股票的波动情况,包括开盘价、收盘价、最高价和最低…...
【ISO 14229-1:2023 UDS诊断全量测试用例清单系列:第二节】
ISO 14229-1:2023 UDS诊断服务测试用例全解析(ECU复位0x11服务) 作者:车端域控测试工程师 更新日期:2025-02-12 关键词:UDS诊断协议、ECU复位服务、0x11服务、ISO 14229-1:2023 二、ECU复位服务(0x11服务&…...
Unity URP的2D光照简介
官网工程,包括2d光照,动画,动效介绍: https://unity.com/cn/blog/games/happy-harvest-demo-latest-2d-techniques https://docs.unity3d.com/6000.0/Documentation/Manual/urp/Lights-2D-intro.html 人物脸部光照细节和脚上的阴影…...
自学人工智能大模型,满足7B模型的训练和微调以及推理,预算3万,如何选购电脑
如果你的预算是 3万元人民币,希望训练和微调 7B 参数规模的人工智能大模型(如 LLaMA、Mistral 等),你需要一台高性能的深度学习工作站。在这个预算范围内,以下是推荐的配置: 1. 关键硬件配置 (1) GPU (显卡…...
shell脚本自动安装MySQL8
环境:centos7版本:8.0.28安装包:mysql-8.0.28-linux-glibc2.12-x86_64.tar.xz 二进制包要求:安装包和shell脚本在同一目录下执行方式:sudo ./install_mysql8.sh #!/bin/bash# 定义MySQL安装目录和压缩包名称MYSQL_DIR…...
使用亚马逊针对 PyTorch 和 MinIO 的 S3 连接器进行模型检查点处理
2023 年 11 月,Amazon 宣布推出适用于 PyTorch 的 S3 连接器。适用于 PyTorch 的 Amazon S3 连接器提供了专为 S3 对象存储构建的 PyTorch 数据集基元(数据集和数据加载器)的实现。它支持用于随机数据访问模式的地图样式数据集和用于流式处理…...
DeepAR:一种用于时间序列预测的深度学习模型
介绍 DeepAR是一种基于递归神经网络(RNN)的时间序列预测模型,由亚马逊在2017年提出。它特别适用于处理多变量时间序列数据,并能够生成概率预测。DeepAR通过联合训练多个相关时间序列来提高预测性能,从而在实际应用中表…...
【无标题】《On Java中文版基础卷+进阶卷》书评
Java语言作为最热门的编程语言之一,关于Java语言的书更是数不胜数,而我选择这本《On Java中文版基础卷进阶卷》作为我学习Java语言的工具书。这本书的作者是《Java编程思想》的Bruce Eckel,《Java编程思想》在之前可谓是鼎鼎有名,…...
【鸿蒙开发】第二十九章 Stage模型-应用上下文Context、进程、线程
目录 1 Stage模型基本概念 1.1 开发流程 3 应用上下文Context的典型使用场景 3.1 获取应用文件路径 3.2 获取和修改加密分区 3.3 获取本应用中其他Module的Context 3.4 订阅进程内UIAbility生命周期变化 4 进程 4.1 概述 5 线程 5.1 线程类型 5.2 使用EventHub进行线…...
AI-Engine-Direct-Helper 快速上手及环境配置
AI-Engine-Direct-Helper 是一个强大的工具,旨在简化和加速在 Qualcomm 平台上开发 AI 应用的过程。通过提供统一的 API、跨平台支持和高效的执行性能,它为开发者提供了一个灵活且高效的开发环境。如果您正在使用 Qualcomm 平台进行 AI 开发,…...
网络安全产品架构图 网络安全相关产品
一、信息安全产品分类 背景 美国将网络和信息安全产品分了9类:鉴别、访问控制、入侵检测、防火墙、公钥基础设施、恶意程序代码防护、漏洞扫描、取证、介质清理或擦除。中国公安部将网络和信息安全产品分了7类:操作系统安全、数据库安全、网络安全、病毒…...
日常知识点之面试后反思裸写string类
1:实现一个字符串类。 简单汇总 最简单的方案,使用一个字符串指针,以及实际字符串长度即可。 参考stl的实现,为了提升string的性能,实际上单纯的字符串指针和实际长度是不够了,如上,有优化方案…...
Linux(socket网络编程)TCP连接
Linux(socket网络编程)TCP连接 基础文件目录函数系统进程控制函数fork()exec系列函数void abort(void)void assert(int expression)void exit(int status)void _exit(int status)int atexit(void (*func)(void))int on_exit(void (*function)(int,void*)…...
深入 JVM 虚拟机:字符串常量池演变与 intern() 方法工作原理解析
🚀 作者主页: 有来技术 🔥 开源项目: youlai-mall ︱vue3-element-admin︱youlai-boot︱vue-uniapp-template 🌺 仓库主页: GitCode︱ Gitee ︱ Github 💖 欢迎点赞 👍 收藏 ⭐评论 📝 如有错误敬请纠正! 前言 在 Java 开发中,字符串常量池(String Constant…...
从零开始学习人工智能
从零开始学习人工智能可以按照以下步骤进行: 一、了解人工智能的基本概念 学习内容:了解人工智能的定义、发展历程、主要研究方向(如机器学习、深度学习、自然语言处理、计算机视觉等)、常见应用(如语音识别、图像识别…...
解锁电商数据宝藏:淘宝商品详情API实战指南
在电商蓬勃发展的今天,数据已成为驱动业务增长的核心引擎。对于商家、开发者以及数据分析师而言,获取精准、实时的商品数据至关重要。而淘宝,作为国内最大的电商平台,其海量商品数据更是蕴含着巨大的价值。 本文将带你深入探索淘…...
Gui-Guider1.8.1 数字时钟控件找不到定义,无法编译
我们在Gui-Guider中使用的一些控件,生成后会发现在LVGL源码中找不到该控件的定义,这时因为Gui-Guider中的一些控件是其自己编写的而不是LVGL提供的,那么我们该如何应用呢?这里拿Digital Clock数字时钟控件举例: 这里我…...
多模态模型详解
多模态模型是什么 多模态模型是一种能够处理和理解多种数据类型(如文本、图像、音频、视频等)的机器学习模型,通过融合不同模态的信息来提升任务的性能。其核心在于利用不同模态之间的互补性,增强模型的鲁棒性和准确性。 如何融合…...
Unity3D实现显示模型线框(shader)
系列文章目录 unity工具 文章目录 系列文章目录👉前言👉一、效果展示👉二、第一种方式👉二、第二种方式👉壁纸分享👉总结👉前言 在 Unity 中显示物体线框主要基于图形渲染管线和特定的渲染模式。 要显示物体的线框,通常有两种常见的方法:一种是利用内置的渲染…...
【实测】用全志A733平板搭建一个端侧Deepseek算力平台
随着DeepSeek 的蒸馏技术的横空出世,端侧 SoC 芯片上运行大模型成为可能。那么端侧芯片跑大模型的效果如何呢?本文将在全志 A733 芯片平台上部署一个 DeepSeek-R1:1.5B 模型,并进行实测效果展示。 端侧平台环境 设备:全志A733平板…...
新数据结构(7)——Object
Object类是所有类的父类,在 Java 中,每个类都直接或间接地继承自Object类,也就是说所有类都是object类的子类可以使用Object里的方法。 equals()和hashCode()是Java中Object类所包含的两个关键方法,下面将介绍两个方法。 和equa…...
数据结构-栈和队列的应用
目录 前言一、栈的应用(迷宫问题)1.1 问题描述1.2 算法选择1.3 算法精化1.4 算法实现1.5 问题结果 二、队列的应用(农夫过河问题)2.1 问题描述2.2 算法选择2.3 算法精化2.4 算法实现2.5 问题结果 总结 前言 本篇文章使用两个例子…...
【JavaScript】异步编程汇总
异步编程解决方案: 回调函数PromiseGeneratorawait / async 回调函数 回调函数是早期处理异步编程的主要方式,虽然它本身存在很多的缺陷,比如那个时候对于复杂的异步处理常常会出现回调地狱。 但是因为 JavaScript 中当时并没有很好的API来帮…...
【AI系列】从零开始学习大模型GPT (2)- Build a Large Language Model (From Scratch)
前序文章 【AI系列】从零开始学习大模型GPT (1)- Build a Large Language Model (From Scratch) Build a Large Language Model 背景第1章:理解大型语言模型第2章:处理文本数据第3章:编码Attention机制什么是Attention机制?Attention机制的基本原理数学表示应用总结为什么要…...
动态规划——路径问题②
文章目录 931. 下降路径最小和算法原理代码实现 64. 最小路径和算法原理代码实现 174. 地下城游戏算法原理代码实现 931. 下降路径最小和 题目链接:931. 下降路径最小和 算法原理 状态表示: 经验题目要求:dp[i][j]表示到达[i,j]位置时&…...
【每日关注】科技圈重要动态
时代新动态 2025 年 2 月 12 日科技圈重要动态总结全球 AI 治理新进展巴黎 AI 宣言签署,美英缺席 科技巨头合作与竞争苹果联姻阿里开发中国版AI功能DeepSeek生态持续扩展OpenAI拒绝马斯克收购,矛盾公开化 汽车行业动态小米汽车销量跃居新势力第二比亚迪智…...