【网络入侵检测】基于源码分析Suricata的IP分片重组
【作者主页】只道当时是寻常
【专栏介绍】Suricata入侵检测。专注网络、主机安全,欢迎关注与评论。
目录
目录
1.概要
2. 配置信息
2.1 名词介绍
2.2 defrag 配置
3. 代码实现
3.1 配置解析
3.1.1 defrag配置
3.1.2 主机系统策略
3.2 分片重组模块
3.2.1分片追踪器(DefragTracker )
3.2.2 获取分片追踪器(DefragGetTracker)
3.2.3 分片插入(DefragInsertFrag)
3.2.3.1 分片冲突策略
3.2.3.1.1 DEFRAG_POLICY_BSD
3.2.3.1.2 DEFRAG_POLICY_BSD_RIGHT
3.2.3.1.3 DEFRAG_POLICY_LINUX
3.2.3.1.4 DEFRAG_POLICY_WINDOWS
3.2.3.1.5 DEFRAG_POLICY_SOLARIS
3.2.3.2 获取主机系统策略
1.概要
👋 本文针对网络入侵检测中 Suricata 的 IP 分片重组模块展开源码分析。IP 分片重组是网络数据传输关键,对 NIDS 执行 DPI 至关重要。Suricata 作为开源高性能网络威胁检测引擎,通过分析其 IP 分片重组模块源码,解析该模块处理 IP 分片数据、监视重组数据包,并将重组数据传递给后续模块的过程,以确保检测准确完整。文中主要包含Suricata中分片配置、分片重组以及解决重组冲突信息。
2. 配置信息
2.1 名词介绍
IP 分片 | IP 分片是因不同网络链路 MTU 不同,当 IP 数据包大小超链路 MTU 时,将其拆成多个小数据包的机制。 |
IP 分片流 | 单个 IP 报文经分片处理后,由其形成的多个分片所构成的传输流,被称为 IP 分片流,其中各分片报文的 IP 包头 ID 标识保持一致。 |
分片重组引擎 | Suricata 中专门用于对 IP 分片报文实施内部重组的功能模块。 |
2.2 defrag 配置
在 Suricata 的配置文件中,defrag 关键字包含的配置信息用于配置分片重组引擎。其默认配置信息如下:
defrag:memcap: 32mb# memcap-policy: ignorehash-size: 65536trackers: 65535 # number of defragmented flows to followmax-frags: 65535 # number of fragments to keep (higher than trackers)prealloc: yestimeout: 60# Enable defrag per host settings
# host-config:
#
# - dmz:
# timeout: 30
# address: [192.168.1.0/24, 127.0.0.0/8, 1.1.1.0/24, 2.2.2.0/24, "1.1.1.1", "2.2.2.2", "::1"]
#
# - lan:
# timeout: 45
# address:
# - 192.168.0.0/24
# - 192.168.10.0/24
# - 172.16.14.0/24
-
memcap:设置分片重组引擎可申请的最大使用内存,这限制了碎片整理过程中内存的使用量。
-
memcap-policy:[drop-packet/pass-packet/reject/ignore(默认)],适用于IPS模式,例如在分片重组时空间申请失败等因素导致无法重组该分片时,对该分片采取的策略。
-
hash-size:设置哈希表中能存储的元素的上限。
-
trackers:设置预先申请的分片追踪器(DefragTracker )的数量,一般和 prealloc 配合使用,prealloc 为 yes,则申请执行数量的DefragTracker 存储在defragtracker_spare_q结构中,否则不申请。
-
max-frags:设置最大分片数量。
-
prealloc:见 "trackers" 字段解释。
-
timeout:设置分片重组超时时间,默认 60s。
-
host-config: 针对特定主机单独设置分片重组策略。
-
timeout:设置分片重组超时时间,默认 60s。
-
address:设置主机IP地址。
-
3. 代码实现
3.1 配置解析
3.1.1 defrag配置
DefragInit 函数是Suricata 解析配置文件中 Defrag 配置信息的入口函数,DefragPolicyLoadFromConfig 函数用于解析 defrag.host-config 相关的配置信息,DefragInitConfig 函数用于解析其它配置信息。
3.1.2 主机系统策略
在Suricata中 SCHInfoLoadFromConfig 函数主要用于加载配置文件中 host-os-policy 相关的配置信息。
host-os-policy 的配置格式如下所示,分号前面为操作系统类型,后面列表中包含主机的IP地址,不同的IP地址可使用逗号分割。Suricata依据用户配置的IP地址区分主机系统类型。
# Host specific policies for defragmentation and TCP stream
# reassembly. The host OS lookup is done using a radix tree, just
# like a routing table so the most specific entry matches.
host-os-policy:windows: [0.0.0.0/0]bsd: []bsd_right: []old_linux: []linux: [10.0.0.0/8, 192.168.1.100, "8762:2352:6241:7245:E000:0000:0000:0000"]old_solaris: []solaris: ["::1"]hpux10: []hpux11: []irix: []macos: []vista: []windows2k3: []
下面sc_hinfo_os_policy_map 结构用于将配置信息中主机类型转换成宏变量。
/** Enum map for the various OS flavours */
SCEnumCharMap sc_hinfo_os_policy_map[ ] = {{ "none", OS_POLICY_NONE },{ "bsd", OS_POLICY_BSD },{ "bsd-right", OS_POLICY_BSD_RIGHT },{ "old-linux", OS_POLICY_OLD_LINUX },{ "linux", OS_POLICY_LINUX },{ "old-solaris", OS_POLICY_OLD_SOLARIS },{ "solaris", OS_POLICY_SOLARIS },{ "hpux10", OS_POLICY_HPUX10 },{ "hpux11", OS_POLICY_HPUX11 },{ "irix", OS_POLICY_IRIX },{ "macos", OS_POLICY_MACOS },{ "windows", OS_POLICY_WINDOWS },{ "vista", OS_POLICY_VISTA },{ "windows2k3", OS_POLICY_WINDOWS2K3 },{ NULL, -1 },
};
3.2 分片重组模块
Defrag 函数作为分片重组引擎的入口函数,在网络数据包解码过程中发挥着关键作用。当解码进入网络层时,会根据数据包的 IP 版本调用 DecodeIPV4 或 DecodeIPV6 函数进行处理(有关具体的解码流程以及这两个函数的详细介绍,可查阅 【网络入侵检测】基于源码分析Suricata的解码模块)。在调用这两个解码函数期间,Defrag 函数可能会被触发。IPv4 报文触发的条件是:IP 包头中的偏移字段值大于零,或者更多分片标志位(MF)被设置为 1。只有满足这些条件,才会调用 Defrag 函数对分片数据包进行重组操作。IPv6不是本文重点,本文不再关注。
下面是 Suricata 源码中对于IPv4包头是否分片判断:
int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p,const uint8_t *pkt, uint16_t len)
{... .../* If a fragment, pass off for re-assembly. */if (unlikely(IPV4_GET_IPOFFSET(p) > 0 || IPV4_GET_MF(p) == 1)) {Packet *rp = Defrag(tv, dtv, p);if (rp != NULL) {PacketEnqueueNoLock(&tv->decode_pq, rp);}p->flags |= PKT_IS_FRAGMENT;return TM_ECODE_OK;}... ...
}
下面是分片重组模块四个主要函数:
-
Defrag:分片重组入口函数。
-
DefragGetTracker:获取分片追踪器(DefragTracker )。
-
DefragInsertFrag:执行分片重组操作。
-
DefragTrackerRelease:执行 DefragTracker 结构引用计数减一操作,并不是释放该对象。
下面是分片重组模块整体设计:
3.2.1分片追踪器(DefragTracker )
在 Suricata 中 DefragTracker 这个结构体尤为重要,该结构体用于跟踪和管理 IP 分片重组的过程。它的主要作用是记录与特定 IP 分片流相关的信息,以便在接收到所有分片后能够正确地重组原始数据包。下面是该结构体的结构:
/*** A defragmentation tracker. Used to track fragments that make up a* single packet.*/
typedef struct DefragTracker_ {SCMutex lock; /**< Mutex for locking list operations on* this tracker. */uint16_t vlan_id[VLAN_MAX_LAYERS]; /**< VLAN ID tracker applies to. */uint32_t id; /**< IP ID for this tracker. 32 bits for IPv6, 16* for IPv4. */uint8_t proto; /**< IP protocol for this tracker. */uint8_t policy; /**< Reassembly policy this tracker will use. */uint8_t af; /**< Address family for this tracker, AF_INET or* AF_INET6. */uint8_t seen_last; /**< Has this tracker seen the last fragment? */uint8_t remove; /**< remove */Address src_addr; /**< Source address for this tracker. */Address dst_addr; /**< Destination address for this tracker. */int datalink; /**< datalink for reassembled packet, set by first fragment */SCTime_t timeout; /**< When this tracker will timeout. */uint32_t host_timeout; /**< Host timeout, statically assigned from the yaml *//** use cnt, reference counter */SC_ATOMIC_DECLARE(unsigned int, use_cnt);struct IP_FRAGMENTS fragment_tree;/** hash pointers, protected by hash row mutex/spin */struct DefragTracker_ *hnext;struct DefragTracker_ *hprev;/** list pointers, protected by tracker-queue mutex/spin */struct DefragTracker_ *lnext;struct DefragTracker_ *lprev;
} DefragTracker;
下面我们挑选几个主要的变量进行解释:
-
vlan_id:记录 VLAN ID,用于标识分片所属的 VLAN 网络。
-
id:IP 分片的标识符(IP ID),用于区分不同的分片流。
-
proto: IP 协议类型(如 TCP、UDP 等),用于确定分片所属的协议。
-
policy:分片重组策略,不同的主机系统在遇到重组冲突时遵循的重组策略是不同的。
-
af:地址族,标识是 IPv4 (AF_INET) 还是 IPv6 (AF_INET6)。
-
seen_last:标记是否已经接收到最后一个分片。
-
remove:标记该跟踪器是否需要被移除。
-
src_addr:记录分片流的源地址。
-
dst_addr:记录分片流的目的地址。
-
datalink:数据链路层类型,由第一个分片设置。
-
timeout:超时时间,用于确定何时丢弃未完成的分片流。
-
fragment_tree: 用于存储分片的红黑树,按分片偏移量排序。
-
hnext 和 hprev: 哈希表指针,用于在哈希表中链接多个跟踪器。
-
lnext 和 lprev: 链表指针,用于在跟踪器队列中链接多个跟踪器。
👋 综上所述,我们能够明确,每个不同的 IP 分片流都与唯一的 DefragTracker 结构相对应。DefragTracker 结构借助红黑树,按照偏移顺序对当前 IP 分片流中的各个数据包进行存储。后续的分片存储、数据包重组等操作,均依赖这一结构体展开。
3.2.2 获取分片追踪器(DefragGetTracker)
在 Defrag 函数对分片包完成统计操作后,会调用 DefragGetTracker 函数,以查找当前分片报文是否存在对应的 DefragTracker 结构。若存在,则返回该 DefragTracker 结构;若不存在,则创建一个新的 DefragTracker 结构,用于存储该分片包所在分片流的相关信息。具体流程如下图所示:
3.2.3 分片插入(DefragInsertFrag)
调用 DefragGetTracker 后已经获取当前分片关联的 DefragTracker 对象,接着根据当前分片的偏移值,将分片插入到分片队列中。下面是分片插入操作流程图:
3.2.3.1 分片冲突策略
分片在重组的过程中可能出现新的分片与旧的分片出现冲突或者覆盖的现象,如下图所示(参考自TCP IP协议 卷2 第十章):
通过观察上图可以看到分片5与分片1和分片2发生重叠,分片7和分片3发生重叠,分片6与分片4发生重叠。其中分片1、2、3、4先到达目标主机,分片5、6、7后到达主机。
👋 为什么分片在传输过程中出现重叠现象?
在正常的网络通信中,IP分片的“Fragment Offset”字段应确保各分片数据在重组时无重叠。然而,攻击者可以故意设置多个分片的偏移量和长度,使它们在重组时发生重叠。
例如,攻击者可能发送两个分片:
分片A:偏移量为0,长度为100字节
分片B:偏移量为50,长度为100字节
在这种情况下,分片B的前50字节将覆盖分片A的后50字节,导致数据重叠。
👋 发生分片重叠时应该怎么处理?
不同操作系统和网络设备在处理重叠分片时的行为可能不同:
某些系统可能保留第一个到达的分片数据,忽略后续重叠部分。
另一些系统可能使用后到达的分片数据覆盖先前的内容。
还有的系统可能在检测到重叠时直接丢弃整个数据包。
Suricata 支持多种分片重组策略来适配多种不同的操作系统,而在配置文件中 host-os-policy 配置可指定目标主机系统类型。
3.2.3.1.1 DEFRAG_POLICY_BSD
该策略遵循左侧优先法,即优先保留左侧偏移较小的分片数据。如果新分片与旧分片完全重合的情况下,优先保留旧分片。如果新分片左侧偏移与旧分片左侧偏移相等的情况下,优先裁剪新分片数据。
该部分逻辑代码实现如下所示:
/*** Insert a new IPv4/IPv6 fragment into a tracker.** \todo Allocate packet buffers from a pool.*/
static Packet *
DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, Packet *p)
{... ...case DEFRAG_POLICY_BSD:if (frag_offset < prev->offset + prev->data_len) {if (prev->offset <= frag_offset) { /* We prefer the data from the previous* fragment, so trim off the data in the new* fragment that exists in the previous* fragment. */uint16_t prev_end = prev->offset + prev->data_len;if (prev_end > frag_end) { /* Just skip. *//* TODO: Set overlap flag. */goto done;}ltrim = prev_end - frag_offset;if ((next != NULL) && (frag_end > next->offset)) {next->ltrim = frag_end - next->offset;}goto insert;}/* If the end of this fragment overlaps the start* of the previous fragment, then trim up the* start of previous fragment so this fragment is* used.** See:* DefragBsdSubsequentOverlapsStartOfOriginal.*/if (frag_offset <= prev->offset && frag_end > prev->offset + prev->ltrim) {uint16_t prev_ltrim = frag_end - prev->offset;if (prev_ltrim > prev->ltrim) {prev->ltrim = prev_ltrim;}}if ((next != NULL) && (frag_end > next->offset)) {next->ltrim = frag_end - next->offset;}goto insert;}break;... ...
}
3.2.3.1.2 DEFRAG_POLICY_BSD_RIGHT
该策略遵循右侧覆盖策略,即右边的分片覆盖前面的分片数据。
3.2.3.1.3 DEFRAG_POLICY_LINUX
该策略遵循左侧优先法,即优先保留左侧偏移较小的分片数据。如果新分片与旧分片完全重合的情况下,优先保留新分片。如果新分片左侧偏移与旧分片左侧偏移相等的情况下,优先裁剪旧分片数据。
该部分逻辑代码实现如下所示:
/*** Insert a new IPv4/IPv6 fragment into a tracker.** \todo Allocate packet buffers from a pool.*/
static Packet *
DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, Packet *p)
{... ...case DEFRAG_POLICY_LINUX:/* Check if new fragment overlaps the end of previous* fragment, if it does, trim the new fragment.** Old: AAAAAAAA AAAAAAAA AAAAAAAA* New: BBBBBBBB BBBBBBBB BBBBBBBB* Res: AAAAAAAA AAAAAAAA AAAAAAAA BBBBBBBB*/if (prev->offset + prev->ltrim < frag_offset + ltrim &&prev->offset + prev->data_len > frag_offset + ltrim) {ltrim += prev->offset + prev->data_len - frag_offset;}/* Check if new fragment overlaps the beginning of* previous fragment, if it does, tim the previous* fragment.** Old: AAAAAAAA AAAAAAAA* New: BBBBBBBB BBBBBBBB BBBBBBBB* Res: BBBBBBBB BBBBBBBB BBBBBBBB*/if (frag_offset + ltrim < prev->offset + prev->ltrim &&frag_end > prev->offset + prev->ltrim) {prev->ltrim += frag_end - (prev->offset + prev->ltrim);goto insert;}/* If the new fragment completely overlaps the* previous fragment, mark the previous to be* skipped. Re-assembly would succeed without doing* this, but this will prevent the bytes from being* copied just to be overwritten. */if (frag_offset + ltrim <= prev->offset + prev->ltrim &&frag_end >= prev->offset + prev->data_len) {prev->skip = 1;goto insert;}break;... ...
}
3.2.3.1.4 DEFRAG_POLICY_WINDOWS
该策略遵循"先到先得"原则,即尽量保全先到来的数据包分片。除非新分片包含且不完全重合于旧分片的情况下,保留新分片。如果新分片左侧偏移与旧分片左侧偏移相等的情况下,优先裁剪新分片数据。
该部分逻辑代码实现如下所示:
/*** Insert a new IPv4/IPv6 fragment into a tracker.** \todo Allocate packet buffers from a pool.*/
static Packet *
DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, Packet *p)
{... ...case DEFRAG_POLICY_WINDOWS:/* If new fragment fits inside a previous fragment, drop it. */if (frag_offset + ltrim >= prev->offset + ltrim &&frag_end <= prev->offset + prev->data_len) {goto done;}/* If new fragment starts before and ends after* previous fragment, drop the previous fragment. */ if (frag_offset + ltrim < prev->offset + ltrim &&frag_end > prev->offset + prev->data_len) {prev->skip = 1;goto insert;}/* Check if new fragment overlaps the end of previous* fragment, if it does, trim the new fragment.** Old: AAAAAAAA AAAAAAAA AAAAAAAA* New: BBBBBBBB BBBBBBBB BBBBBBBB* Res: AAAAAAAA AAAAAAAA AAAAAAAA BBBBBBBB*/if (frag_offset + ltrim > prev->offset + prev->ltrim &&frag_offset + ltrim < prev->offset + prev->data_len) { ltrim += prev->offset + prev->data_len - frag_offset; goto insert;}/* If new fragment starts at same offset as an* existing fragment, but ends after it, trim the new* fragment. */if (frag_offset + ltrim == prev->offset + ltrim &&frag_end > prev->offset + prev->data_len) {ltrim += prev->offset + prev->data_len - frag_offset;goto insert;}break;... ...
}
3.2.3.1.5 DEFRAG_POLICY_SOLARIS
该策略遵循左侧优先法,即优先保留左侧偏移较小的分片数据。如果新分片与旧分片完全重合的情况下,优先保留旧分片。如果新分片左侧偏移与旧分片左侧偏移相等的情况下,优先裁剪新分片数据。
该部分逻辑代码实现如下所示:
/*** Insert a new IPv4/IPv6 fragment into a tracker.** \todo Allocate packet buffers from a pool.*/
static Packet *
DefragInsertFrag(ThreadVars *tv, DecodeThreadVars *dtv, DefragTracker *tracker, Packet *p)
{... ...case DEFRAG_POLICY_SOLARIS:if (frag_offset < prev->offset + prev->data_len) {if (frag_offset >= prev->offset) {ltrim = prev->offset + prev->data_len - frag_offset;}if ((frag_offset < prev->offset) &&(frag_end >= prev->offset + prev->data_len)) {prev->skip = 1;}goto insert;}break;... ...
}
3.2.3.2 获取主机系统策略
在Suricata的配置文件中通过host-os-policy关键字已经配置好主机系统策略,而在初始化DefragTracker对象时,即调用DefragTrackerInit函数时,会通过当前分片的IP地址,结合host-os-policy配置来选择重组策略。
调用逻辑如下所示:
在 DefragGetOsPolicy 函数中,Suricata会将不同的系统策略归为7类。注意,如果未配置,默认重组策略为DEFRAG_POLICY_BSD。
系统策略 | 分片重组策略 |
DEFRAG_POLICY_BSD | OS_POLICY_BSD |
OS_POLICY_HPUX10 | |
OS_POLICY_IRIX | |
DEFRAG_POLICY_BSD_RIGHT | OS_POLICY_BSD_RIGHT |
DEFRAG_POLICY_LINUX | OS_POLICY_OLD_LINUX |
OS_POLICY_LINUX | |
DEFRAG_POLICY_FIRST | OS_POLICY_OLD_SOLARIS |
OS_POLICY_HPUX11 | |
OS_POLICY_MACOS | |
OS_POLICY_FIRST | |
DEFRAG_POLICY_SOLARIS | OS_POLICY_SOLARIS |
DEFRAG_POLICY_WINDOWS | OS_POLICY_WINDOWS |
OS_POLICY_VISTA | |
OS_POLICY_WINDOWS2K3 | |
DEFRAG_POLICY_LAST | OS_POLICY_LAST |
分片重组策略结构如下所示:
/** Fragment reassembly policies. */
enum defrag_policies {DEFRAG_POLICY_FIRST = 1,DEFRAG_POLICY_LAST,DEFRAG_POLICY_BSD,DEFRAG_POLICY_BSD_RIGHT,DEFRAG_POLICY_LINUX,DEFRAG_POLICY_WINDOWS,DEFRAG_POLICY_SOLARIS,DEFRAG_POLICY_DEFAULT = DEFRAG_POLICY_BSD,
};
相关文章:

【网络入侵检测】基于源码分析Suricata的IP分片重组
【作者主页】只道当时是寻常 【专栏介绍】Suricata入侵检测。专注网络、主机安全,欢迎关注与评论。 目录 目录 1.概要 2. 配置信息 2.1 名词介绍 2.2 defrag 配置 3. 代码实现 3.1 配置解析 3.1.1 defrag配置 3.1.2 主机系统策略 3.2 分片重组模块 3.2.1…...
Spring框架请求注解
Spring框架请求注解 1.RequestParam 作用:从请求的 查询参数(Query Parameters) 或 表单数据(Form Data) 中提取参数。适用场景: GET 请求的 URL 参数(如 /users?nameTom&age20ÿ…...

LVGL简易计算器实战
文章目录 📁 文件结构建议🔹 eval.h 表达式求值头文件🔹 eval.c 表达式求值实现文件(带详细注释)🔹 ui.h 界面头文件🔹 ui.c 界面实现文件🔹 main.c 主函数入口✅ 总结 项目效果&…...
【FMMT】基于模糊多模态变压器模型的个性化情感分析
遇到很难的文献看不懂,不应该感到气馁,应该激动,因为外审估计也看不太懂,那么学明白了可以吓唬他 缺陷一:输入依赖性与上下文建模不足 缺陷描述: 传统自注意力机制缺乏因果关系,难以捕捉序列历史背景多模态数据间的复杂依赖关系未被充分建模CNN/RNN类模型在…...
聊一聊接口测试依赖第三方服务变更时如何处理?
目录 一、依赖隔离与模拟 二、契约测试 三、版本控制与兼容性 四、变更监控与告警 五、容错设计 六、自动化测试维护 七、协作机制与文档自动化 第三方API突然改了参数或者返回结构,导致我们的测试用例失败,这时候该怎么办呢?首先想到…...

代码随想录算法训练营第60期第三十四天打卡
大家好,我们今天的内容依旧是贪心算法,我们上次的题目主要是围绕多维问题,那种时候我们需要分开讨论,不要一起并发进行很容易顾此失彼,那么我们今天的问题主要是重叠区间问题,又是一种全新的贪心算法思想&a…...
Midscene.js Chrome 插件实战:基于 AI 驱动 WEB UI 自动化测试「喂饭教程」
Midscene.js Chrome 插件实战:基于 AI 驱动 WEB UI 自动化测试「喂饭教程」 前言一、Midscene.js 简介二、环境准备与插件安装1. 安装 Chrome 插件2. 配置模型与 API Key三、插件界面与功能总览四、实战演练:用自然语言驱动网页自动化1. 典型场景一(Action):账号登录步骤一…...
JVM——方法内联之去虚化
引入 在Java虚拟机的即时编译体系中,方法内联是提升性能的核心手段,但面对虚方法调用(invokevirtual/invokeinterface)时,即时编译器无法直接内联,必须先进行去虚化(Devirtualizationÿ…...
Objective-C Block 底层原理深度解析
Objective-C Block 底层原理深度解析 1. Block 是什么? 1.1 Block 的本质 Block 是 Objective-C 中的特殊对象,实现了匿名函数的功能 通过 isa 指针继承自 NSObject,可以响应(如 copy、retain、release)等内存管理方…...

关于IDE的相关知识之二【插件推荐】
成长路上不孤单😊😊😊😊😊😊 【14后😊///计算机爱好者😊///持续分享所学😊///如有需要欢迎收藏转发///😊】 今日分享关于ide插件推荐的相关内容!…...
Python+Streamlit实现登录页
PythonStreamlit实现登录页 Streamlit 是一个开源的 Python 库,专为数据科学家和机器学习工程师设计,用于快速构建交互式 Web 应用。 其核心功能与特点包括: 1.快速原型开发 2.交互式数据展示 3.极简开发 4.实时更新 5.内置组件 6.无前端依赖…...
RDD案例数据清洗
在 Spark 中,RDD(Resilient Distributed Dataset)是分布式数据集的基本抽象。数据清洗是数据预处理中的一个重要步骤,通常包括去除重复数据、过滤无效数据、转换数据格式等操作。以下是一个使用 RDD 进行数据清洗的完整示例。 示…...
按键精灵ios脚本新增元素功能助力辅助工具开发(三)
元素节点功能(iOSElement) 在按键精灵 iOS 新版 APP v2.2.0 中,新增了元素节点功能 iOSElement,该功能包含共 15 个函数。这一功能的出现,为开发者在处理 iOS 应用界面元素时提供了更为精准和高效的方式。通过这些函…...

Axure RP9:列表新增
文章目录 列表新增思路新增按钮操作说明保存新增交互设置列表新增 思路 利用中继器新增行实现列表新增功能 新增按钮操作说明 工具栏中添加新增图标及标签,在图标标签基础上添加热区;对热区添加鼠标单击时交互事件,同步插入如下动作:显示/隐藏动作,设置目标元件为新增窗…...

06 mysql之DML
一、什么是DML DML 用于操作数据库中的数据。主要命令包括: INSERT:添加数据SELECT:查询数据UPDATE:修改数据DELETE:删除数据 二、插入数据(INSERT) 2.1 插入单条记录 -- 插入学生记录&…...
游戏引擎学习第277天:稀疏实体系统
回顾并为今天定下基调 上次我们结束的时候,基本上已经控制住了跳跃的部分,达到了我想要的效果,现在我们主要是在等待一些新的艺术资源。因此,等新艺术资源到位后,我们可能会重新处理跳跃的部分,因为现在的…...

【最新版】likeshop连锁点餐系统-PHP版+uniapp前端全开源
一.系统介绍 likeshop外卖点餐系统适用于茶饮类的外卖点餐场景,搭建自己的一点点、奈雪、喜茶点餐系统。 系统基于总部多门店的连锁模式,拥有门店独立管理后台,支持总部定价和门店定价LBS定位点餐,可堂食可外卖。无论运营还是二开…...
机器学习之决策树模型:从基础概念到条件类型详解
机器学习之决策树模型:从基础概念到条件类型详解 摘要:本文深入探讨决策树模型的概念、构成以及不同条件类型。首先介绍决策树的基本结构和工作原理,随后详细阐述轴心对齐条件与倾斜条件、二元条件与非二元条件的差异及应用场景,…...
网络编程(一)网络编程入门
本节课学习TCP客户端和服务器端编程架构,其分为分为C/S(客户端/服务器模式)和B/S(浏览器/服务器架构模式)两种模式。接下来我们分别了解这两种模式 C/S模式 C/S模式:服务器首先先启动,并根据客…...
黑名单中的随机数-leetcode710
题目描述 给定一个整数 n 和一个 无重复 黑名单整数数组 blacklist 。设计一种算法,从 [0, n - 1] 范围内的任意整数中选取一个 未加入 黑名单 blacklist 的整数。任何在上述范围内且不在黑名单 blacklist 中的整数都应该有 同等的可能性 被返回。 优化你的算法&am…...

纯Java实现反向传播算法:零依赖神经网络实战
在深度学习框架泛滥的今天,理解算法底层实现变得愈发重要。反向传播(Backpropagation)作为神经网络训练的基石算法,其实现往往被各种框架封装。本文将突破常规,仅用Java标准库实现完整BP算法,帮助开发者: 1) 深入理解BP数学原理。2) 掌握面向对象的神经网络实现。3) 构建可…...

海纳思(Hi3798MV300)机顶盒遇到海思摄像头
海纳思机顶盒遇到海思摄像头,正好家里有个海思Hi3516的摄像头模组开发板,结合机顶盒来做个录像。 准备工作 海纳斯机顶盒摄像机模组两根网线、两个电源、路由器一块64G固态硬盘 摄像机模组和机顶盒都接入路由器的LAN口,确保网络正常通信。 …...
MCP项目实例 - client sever交互
1. 项目概述 项目目标 构建一个本地智能舆论分析系统。 利用自然语言处理和多工具协作,实现用户查询意图的自动理解。 进行新闻检索、情绪分析、结构化输出和邮件推送。 系统流程 用户查询:用户输入查询请求。 提取关键词:从用户查询中…...

Axure应用交互设计:表格跟随菜单移动效果(超长表单)
亲爱的小伙伴,在您浏览之前,烦请关注一下,在此深表感谢!本文如有帮助请订阅 Axure产品经理精品视频课已登录CSDN可点击学习https://edu.csdn.net/course/detail/40420 课程主题:表格跟随菜单移动 主要内容:表格交互设计、动态面板嵌套、拖动时事件、移动动作 应用场景…...

7系列 之 I/O标准和终端技术
背景 《ug471_7Series_SelectIO.pdf》介绍了Xilinx 7 系列 SelectIO 的输入/输出特性及逻辑资源的相关内容。 第 1 章《SelectIO Resources》介绍了输出驱动器和输入接收器的电气特性,并通过大量实例解析了各类标准接口的实现。 第 2 章《SelectIO Logic Resource…...

github 上的 CI/CD 的尝试
效果 步骤 新建仓库设置仓库的 page 新建一个 vite 的项目,改一下 vite.config.js 中的 base 工作流 在项目的根目录下新建一个 .github/workflows/ci.yml 文件,然后编辑一下内容 name: Build & Deploy Vue 3 Appon:push:branches: [main]permi…...
Scala和Go差异
Scala和Go(又称Golang)是两种现代编程语言,各自具有独特的特性和设计哲学。 尽管它们都可以用于构建高性能、可扩展的应用程序,但在许多方面存在显著差异。 Scala和Go的详细比较,涵盖它们的异同点: 1. 语…...

yup 使用 3 - 利用 meta 实现表单字段与表格列的统一结构配置(适配 React Table)
yup 使用 3 - 利用 meta 实现表单字段与表格列的统一结构配置(适配 React Table) Categories: Tools Last edited time: May 11, 2025 7:45 PM Status: Done Tags: form validation, schema design, yup 本文介绍如何通过 Yup 的 meta() 字段࿰…...
类初始化方法
一、类初始化方法 成员初始化列表 class Point {int x, y; public:Point(int a, int b) : x(a), y(b) {} };就地初始化(C11) 声明时初始化。 class Widget {int size 10; // 类内成员初始化vector<int> data{1,2,3}; };特殊情况:静…...

【OpenCV】imread函数的简单分析
目录 1.imread()1.1 imread()1.2 imread_()1.2.1 查找解码器(findDecoder)1.2.2 读取数据头(JpegDecoder-->readHeader)1.2.2.1 初始化错误信息(jpeg_std_error)1.2.2.2 创建jpeg解压缩对象(…...