CS144 Lab1实战记录:实现TCP重组器
文章目录
- 1 实验背景与要求
- 1.1 TCP的数据分片与重组问题
- 1.2 实验具体任务
- 2 重组器的设计架构
- 2.1 整体架构
- 2.2 数据结构设计
- 3 重组器处理的关键场景分析
- 3.1 按序到达的子串(直接写入)
- 3.2 乱序到达的子串(需要存储)
- 3.3 与已处理区域重叠的子串
- 3.4 与待处理子串重叠的情况
- 3.5 超出容量的子串
- 3.6 结束标记处理
- 4 insert方法的实现流程
- 4.1 入口处理
- 4.2 已处理字节的检查
- 4.3 容量限制检查
- 4.4 直接写入处理
- 4.5 子串存储与合并
- 4.6 结束处理
- 5 count_bytes_pending实现
- 6 调试经验
1 实验背景与要求
在网络传输的过程中,TCP协议必须解决一个关键挑战:如何将不可靠的网络上传输的、可能乱序、丢失、重复或重叠的数据包片段重新组装成连续的字节流?这正是Stanford CS144 Lab1中我们要实现的Reassembler(重组器)组件的核心功能。
1.1 TCP的数据分片与重组问题
TCP协议在发送数据时,会将应用层的字节流划分为多个较小的段(segment),每个段封装在一个IP数据包中进行传输。然而,在网络传输过程中,这些数据包可能会:
- 乱序到达:后发送的数据包可能先到达
- 完全丢失:某些数据包永远不会到达目的地
- 重复到达:同一个数据包可能被网络复制并多次传递
- 部分重叠:重传的包可能与原包内容有部分重叠
接收方必须能够处理这些情况,将所有正确接收的数据按照原始顺序重新组装成连续的字节流,并传递给应用层。这就是重组器(Reassembler)需要解决的问题。
1.2 实验具体任务
在Lab1中,我们需要实现一个Reassembler
类,其主要API如下:
// 插入一个新的子字符串,以便重组为一个ByteStream
void insert(uint64_t first_index, std::string data, bool is_last_substring);// 计算重组器内部存储的字节数量
uint64_t count_bytes_pending() const;// 访问输出流的读取器
Reader& reader();
这个重组器要处理以下核心任务:
- 子串的重组:将不同的子串按照它们在原始流中的顺序重新组装
- 对ByteStream的写入:尽快地将重组好的字节写入输出流
- 内部存储管理:对于暂时无法写入(存在空洞)的子串进行存储
- 容量限制:考虑ByteStream容量限制,丢弃超出容量的字节
- 流结束处理:当接收到标记为最后的子串,并且所有数据都已写入时,关闭输出流
Github的实现代码:https://github.com/HeZephyr/minnow
2 重组器的设计架构
2.1 整体架构
重组器的整体架构如下图所示:
重组器处于网络层和应用层之间,负责将网络传输的不可靠、乱序的数据片段转换为应用层可以使用的可靠、有序的字节流。它的内部需要处理两种情况:
- 可以直接写入ByteStream的子串(下一个期望的字节)
- 需要暂时存储的子串(存在空洞,不能立即写入)
2.2 数据结构设计
为了实现重组器的功能,我们需要设计适当的数据结构。这里我选择了以下成员变量:
ByteStream output_; // 输出流
uint64_t next_index_ = 0; // 下一个要写入的字节索引
bool eof_ = false; // 是否收到了标记为最后的子串
uint64_t eof_index_ = 0; // 流的结束索引位置
std::map<uint64_t, std::string> unassembled_; // 存储未组装的子串
这些数据结构的详细说明:
- ByteStream output_:重组器将重组好的数据写入这个流,应用程序从这个流的读取端获取数据
- uint64_t next_index_:表示下一个期望接收的字节的索引位置,初始值为0,每写入一个字节就增加1。用于判断新到的子串是否可以直接写入
- bool eof_:标记是否已收到流的最后一个子串,当收到
is_last_substring=true
的子串时设置为true - uint64_t eof_index_:记录流的总长度(最后一个字节之后的位置),当
next_index_ == eof_index_
时,表示所有数据都已处理完毕 - std::map<uint64_t, std::string> unassembled_:存储那些已接收但因为前面有空洞而不能立即写入的子串,键为子串的起始索引,值为子串内容,使用map可以自动按索引排序,便于查找和合并
这种设计的优势在于:
- 使用有序映射(std::map)能够高效地管理乱序到达的子串
- 通过比较
next_index_
和子串的起始位置,可以快速判断子串是否可以直接写入 - 当空洞被填补时,能够方便地找到并处理下一个连续的子串
3 重组器处理的关键场景分析
在实现重组器时,需要处理多种不同的子串到达场景。以下通过图解分析重组器需要处理的典型情况:
3.1 按序到达的子串(直接写入)
当接收到的子串的起始索引恰好等于当前期望的下一个字节索引(first_index == next_index_
)时,可以直接将该子串写入输出流。这是最简单的情况,不需要任何临时存储。
处理逻辑:
- 将子串内容通过
output_.writer().push(data)
直接写入ByteStream - 更新
next_index_ += data.size()
- 检查是否有后续已存储的子串现在可以连续写入
示例:假设当前next_index_ = 5
,收到子串insert(5, "hello", false)
,可以直接将"hello"写入ByteStream,并更新next_index_ = 10
3.2 乱序到达的子串(需要存储)
当接收到的子串起始索引大于当前期望的下一个字节索引(first_index > next_index_
)时,表示中间存在"空洞"。这种情况下,需要将子串临时存储在unassembled_
映射中,等待空洞被填补。
处理逻辑:
- 检查子串是否超出容量限制
- 如果未超出,将子串存储在
unassembled_[first_index] = data
- 可能需要处理与已存储子串的重叠情况
示例:假设当前next_index_ = 5
,收到子串insert(10, "world", false)
,由于10 > 5
,表示5-9的字节尚未收到,将"world"存储在unassembled_[10] = "world"
,等待空洞被填补。
3.3 与已处理区域重叠的子串
有时接收到的子串可能与已处理的区域有重叠(first_index < next_index_
)。在这种情况下,需要截取未处理的部分进行处理。
处理逻辑:
- 计算重叠部分:
overlap = next_index_ - first_index
- 截取未处理部分:
data.substr(overlap)
- 按照非重叠子串的处理方式继续处理
示例:假设当前next_index_ = 5
,收到子串insert(3, "hello", false)
,字节3-4已处理,只需要处理"llo",截取后处理:data = data.substr(2)
-> “llo”,使用新索引first_index = 5
和新数据"llo"继续处理。
3.4 与待处理子串重叠的情况
当新到达的子串与已经存储在unassembled_
中的子串有重叠时,需要合并这些子串以避免重复存储。
处理逻辑:
- 查找可能重叠的子串:使用
lower_bound
和前向遍历 - 检查前面的子串是否与当前子串重叠
- 检查后面的子串是否与当前子串重叠
- 合并所有重叠的子串,生成一个更大的连续子串
- 更新
unassembled_
映射
示例:假设已存储unassembled_[10] = "world"
,收到新子串insert(8, "hellowr", false)
,检测到重叠:8+8 > 10,合并为一个更大的子串:“hellowrld”,更新unassembled_[8] = "hellowrld"
,并删除原来的条目。
3.5 超出容量的子串
ByteStream有固定容量,而重组器应该尊重这个容量限制。对于超出容量的子串部分,应该直接丢弃。
处理逻辑:
- 计算可接受的最大索引:
acceptable_end = next_index_ + output_.writer().available_capacity()
- 判断子串是否完全超出:
first_index >= acceptable_end
- 对于部分超出的子串,截取有效部分:
actual_end = min(first_index + data.size(), acceptable_end)
示例:假设当前next_index_ = 5
,可用容量为10,可接受的最大索引为5 + 10 = 15
,收到子串insert(12, "hello world", false)
,由于"hello world"长度为11,超出了可接受范围,截取前3个字节"hel"进行处理,丢弃后续字节。
3.6 结束标记处理
当收到标记为最后的子串(is_last_substring = true
)时,需要记录流的结束位置,并在所有数据都处理完毕时关闭输出流。
处理逻辑:
- 设置
eof_ = true
- 计算并记录结束索引:
eof_index_ = first_index + data.size()
- 在每次处理完子串后,检查
next_index_ == eof_index_
- 如果条件满足且
eof_ == true
,调用output_.writer().close()
关闭流
示例:假设已处理到next_index_ = 15
,收到子串insert(15, "end", true)
,设置eof_ = true
,eof_index_ = 15 + 3 = 18
,处理完"end"后,next_index_ = 18
,由于next_index_ == eof_index_
且eof_ == true
,关闭输出流。
4 insert方法的实现流程
4.1 入口处理
首先,处理一些边界情况:
- 空字符串的特殊处理,特别是当它被标记为最后一个子串时
- 记录EOF信息,包括是否到达EOF以及EOF的确切位置
void Reassembler::insert(uint64_t first_index, string data, bool is_last_substring)
{// 处理空字符串情况if (data.empty()) {if (is_last_substring) {eof_ = true;eof_index_ = first_index;if (next_index_ == eof_index_) {output_.writer().close();}}return;}// 更新EOF信息if (is_last_substring) {eof_ = true;eof_index_ = first_index + data.size();}
4.2 已处理字节的检查
接下来,检查子串是否已经完全处理过,如果子串的结束位置不超过当前已处理的位置,则整个子串都已被处理,可以直接返回。
// 丢弃完全在已处理范围内的子串if (first_index + data.size() <= next_index_) {// 子串完全在已处理的范围内,忽略if (eof_ && next_index_ == eof_index_) {output_.writer().close();}return;}
4.3 容量限制检查
然后,我们需要考虑ByteStream的容量限制:
- 计算ByteStream的可用容量
- 确定可接受的最大索引位置
- 对于超出容量的子串,只保留在容量范围内的部分
- 通过截取得到可用的子串部分
// 计算ByteStream可用容量uint64_t available_capacity = output_.writer().available_capacity();// 计算这个子串在可接受范围内的结束位置uint64_t acceptable_end = next_index_ + available_capacity;// 如果子串起始位置超出可接受范围,丢弃if (first_index >= acceptable_end) {return;}// 截取子串中在可接受范围内的部分uint64_t actual_start = max(first_index, next_index_);uint64_t actual_end = min(first_index + data.size(), acceptable_end);// 子串中有效部分的偏移量和长度uint64_t offset = actual_start - first_index;uint64_t length = actual_end - actual_start;// 截取可用部分string usable_data = data.substr(offset, length);uint64_t usable_index = actual_start;
4.4 直接写入处理
如果子串正好是下一个期望的字节,可以直接写入:
- 将可用的子串直接写入ByteStream
- 更新
next_index_
- 检查
unassembled_
中是否有可以继续写入的子串 - 尝试写入尽可能多的连续子串
// 如果可以直接写入输出流if (usable_index == next_index_) {output_.writer().push(usable_data);next_index_ += usable_data.size();// 检查是否有更多可以写入的子串while (!unassembled_.empty()) {auto it = unassembled_.begin();if (it->first > next_index_) {break; // 有空洞,不能继续写入}// 计算这个子串中有多少新的字节uint64_t overlap = next_index_ - it->first;if (overlap < it->second.size()) {string new_data = it->second.substr(overlap);output_.writer().push(new_data);next_index_ += new_data.size();}// 移除已处理的子串unassembled_.erase(it);}
4.5 子串存储与合并
如果子串不能直接写入,需要存储并处理可能的重叠:
- 使用
lower_bound
查找可能重叠的子串 - 检查并合并与前面子串的重叠
- 检查并合并与后面子串的重叠
- 存储合并后的子串
} else if (usable_data.size() > 0) {// 将子串添加到未组装的映射中// 首先检查是否有重叠的子串,可能需要合并auto it = unassembled_.lower_bound(usable_index);// 检查前面的子串if (it != unassembled_.begin()) {auto prev = prev(it);uint64_t prev_end = prev->first + prev->second.size();// 如果前面的子串与当前子串重叠或相邻if (prev_end >= usable_index) {// 合并子串if (prev_end < usable_index + usable_data.size()) {uint64_t extend_len = usable_index + usable_data.size() - prev_end;prev->second += usable_data.substr(usable_data.size() - extend_len);}// 如果完全被前面的子串覆盖,则无需存储if (prev_end >= usable_index + usable_data.size()) {// 检查是否已完成if (eof_ && next_index_ == eof_index_) {output_.writer().close();}return;}// 更新待处理的子串信息usable_index = prev->first;usable_data = prev->second;unassembled_.erase(prev);}}// 检查和合并后面的子串while (it != unassembled_.end() && it->first <= usable_index + usable_data.size()) {uint64_t it_end = it->first + it->second.size();// 如果后面的子串延伸超过当前子串if (it_end > usable_index + usable_data.size()) {uint64_t extend_len = it_end - (usable_index + usable_data.size());usable_data += it->second.substr(it->second.size() - extend_len);}auto to_erase = it;++it;unassembled_.erase(to_erase);}// 存储合并后的子串unassembled_[usable_index] = usable_data;}
4.6 结束处理
最后,检查是否需要关闭输出流:当所有预期的数据都已处理完毕,且已收到标记为最后的子串时,关闭输出流。
// 检查是否已经处理完所有数据if (eof_ && next_index_ == eof_index_) {output_.writer().close();}
}
5 count_bytes_pending实现
除了insert方法外,还需要实现count_bytes_pending
方法来计算未组装的字节数:
- 只计算未处理的部分(排除与已处理区域重叠的部分)
- 由于子串可能有重叠,需要计算每个子串的有效长度
uint64_t Reassembler::count_bytes_pending() const
{uint64_t total = 0;for (const auto& [index, data] : unassembled_) {// 只计算还未处理的字节if (index + data.size() > next_index_) {uint64_t valid_start = max(index, next_index_);total += (index + data.size()) - valid_start;}}return total;
}
6 调试经验
- 最困难的部分是正确处理子串重叠,考虑子串重叠处理的边界情况。实现之前最好使用纸笔推演各种情况,确保边界处理正确。
- 考虑容量限制。需明确区分ByteStream的容量和Reassembler可以存储的字节数,确保两者之和不超过总容量。
- 确定何时检查并关闭输出流。建议在每次处理子串后都检查是否满足关闭条件,确保不会错过关闭时机。
相关文章:
CS144 Lab1实战记录:实现TCP重组器
文章目录 1 实验背景与要求1.1 TCP的数据分片与重组问题1.2 实验具体任务 2 重组器的设计架构2.1 整体架构2.2 数据结构设计 3 重组器处理的关键场景分析3.1 按序到达的子串(直接写入)3.2 乱序到达的子串(需要存储)3.3 与已处理区…...
Linux信号三部曲:产生机制、处理方式与内核接口
Linux系列 文章目录 Linux系列前言一、背景知识铺垫1.1 信号的基本概念1.2 进程对信号的处理 二、信号的产生2.1 前台进程和后台进程2.2 键盘组合键2.3 kill 命令2.4 系统调用2.4.1 signal()接口2.4.2 kill()接口2.4.3 raise()接口2.4.4 abort()接口 总结 前言 Linux中&#x…...
对抗生成进化:基于DNA算法的AIGC检测绕过——让AI创作真正“隐形“
一、技术背景与核心思想 2025年,AIGC检测工具(如Originality.AI 5.0)的识别准确率已达99.3%。本研究提出基于染色体编码的对抗进化框架(CAEF),通过模拟生物进化过程动态优化生成模型,成功将检测…...
探索大语言模型(LLM):马尔可夫链——从诗歌分析到人工智能的数学工具
提出背景与灵感起源 马尔可夫链由俄国数学家安德雷马尔可夫于1906年提出,最初是为了挑战当时概率论中“独立性假设”的局限性。他希望通过研究相依变量序列,证明即使随机变量之间存在依赖关系,大数定律和中心极限定理仍然成立。 灵感来源&am…...
深入解析Java Socket服务器实现:从基础到优雅停机
本文将详细解析一个基于Java Socket实现的服务器程序,涵盖线程池管理、心跳检测、优雅停机等关键特性,并最终提供完整代码实现。 1. 架构概述 这个Socket服务器实现具有以下核心特性: 基于Java原生Socket API实现使用线程池处理客户端连接…...
AI+SWAT模型革命性应用!ArcGIS Pro流域水循环/水生态智能模拟实战;SWAT模型下载 安装 运行 建模流程
⚠️您是否面临: 传统水文模型效率低下? 多源空间数据处理耗时? 复杂生态过程难以量化? 💡当SWAT模型遇见"ArcGIS ProAI": → 传统需要1个月的参数率定缩短至3天 → 多情景分析报告自动生成&a…...
《AI大模型应知应会100篇》第23篇:角色扮演技巧:让AI成为你需要的专家
第23篇:角色扮演技巧:让AI成为你需要的专家 摘要 在当今人工智能快速发展的时代,大模型已经不仅仅是简单的问答工具,它们可以通过角色扮演技巧模拟各类专家身份,从而为用户提供更专业、更有针对性的服务。本文将深入探…...
【17】数据结构之图的遍历篇章
目录标题 图的遍历深度优先遍历 Depth First Search广度优先遍历 Breadth First Search 图的遍历 从图中某一个顶点出发,沿着一些边访遍图中所有的顶点,且使用每个顶点仅被访问一次,这个过程称为图的遍历.Graph Traversal. 其中,…...
【gpt生成-其一】以go语言为例,详细描述一下 :语法规范BNF/EBNF形式化描述
在 Go 语言中通过 EBNF 形式化描述语法规范需要结合语言规范文档的结构,以下是详细实现方法及标准规范示例: 一、Go 语法规范结构(基于 Go 1.21 标准) ebnf 复制 // 基础元素定义 letter "A" ... "Z&quo…...
深度剖析:GPT-3.5与GPT-4的主要区别及架构解析
随着自然语言处理技术的飞速发展,OpenAI推出的各类语言模型备受瞩目。尤其是GPT-3.5和GPT-4这两个版本之间的差异,成为了技术爱好者、研究人员和企业关注的焦点。在这篇文章中,我们将探讨这两个版本的主要区别以及它们的架构特点,…...
协同推荐算法实现的智能商品推荐系统 - [基于springboot +vue]
🛍️ 智能商品推荐系统 - 基于springboot vue 🚀 项目亮点 欢迎来到未来的购物体验!我们的智能商品推荐系统就像您的私人购物顾问,它能读懂您的心思,了解您的喜好,为您精心挑选最适合的商品。想象一下&am…...
【运维学习】lvs + keepalived + 主从dns 项目搭建
需求 主机规划 环境搭建 配置主从dns 主dns 从dns 配置web服务 搭建lvs keepalived 配置master 配置backup 更改dns配置 添加VIP 配置内核参数 更改web配置 添加VIP 配置内核参数 客户端测试 需求 主机规划 主机名IP角色lvs-master192.168.239.105主lvs&#x…...
ESP32-idf学习(二)esp32C3作服务端与电脑蓝牙数据交互
一、当前需求 目前是想利用蓝牙来传输命令,或者一些数据,包括电脑、手机与板子的数据传输,板子与板子之间的数据传输。构思是一个板子是数据接收终端,在电脑或手机下发指令后,再给其他板子相应指令,也需要…...
考道路运输安全员证应具备哪些经验?
考道路运输安全员证,通常没有明确的工作经验年限要求,但具备以下相关经验会对考试有很大帮助: 驾驶经验:报考要求取得相应的机动车驾驶证 1 年以上。有实际驾驶经验,能更好地理解驾驶员的操作规范、疲劳驾驶等问题&…...
ubtuntu安装docker拉取iwebsec镜像
docker安装: --可以在这之前换源(非必要)没有权限直接加sudo sudo apt-get update sudo apt-get upgrade 安装依赖: sudo apt install apt-transport-https ca-certificates curl software-properties-common gnupg lsb-re…...
Using the CubeMX code (一)(GPIO,PWM ,Cube AI,手写数字识别 MNIST,Demo)
该例程对使用CubeMX初始化GPIO做了示范,GPIO使用HAL库进行GPIO编程分为以下几个步骤: 一、例程简述 1. 包含必要的头文件和HAL库的相关头文件 CubeMX初始化会自动包含,对手敲HAL感兴趣的同学可以熟悉下生成的代码框架学习哦~ 2. 初始化GP…...
【第46节】windows程序的其他反调试手段中篇
目录 引言 一、利用SetUnhandledExceptionFilter/Debugger Interrupts 二、Trap Flag 单步标志异常 三、利用SeDebugPrivilege 进程权限 四、利用DebugObject:NtQueryObject() 五、OllyDbg:Guard 六、Software Breakpoint Detection 引言 在程序反调试领域,存…...
【APM】How to enable Trace to Logs on Grafana?
系列文章目录 【APM】Observability Solution 【APM】Build an environment for Traces, Metrics and Logs of App by OpenTelemetry 【APM】NET Traces, Metrics and Logs to OLTP 【APM】How to enable Trace to Logs on Grafana? 前言 本文将介绍如何在Grafana上启用 …...
第十节:性能优化-如何排查组件不必要的重复渲染?
工具:React DevTools Profiler 方法:memo、shouldComponentUpdate深度对比 React 组件性能优化:排查与解决重复渲染问题指南 一、定位性能问题:React DevTools 高级用法 使用 React Developer Tools Profiler 精准定位问题组件&…...
Spring Boot 项目中发布流式接口支持实时数据向客户端推送
1、pom依赖添加 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></dependency>2、事例代码 package com.pojo.prj.controller;import com.pojo.common.core.utils.String…...
SpringBoot整合Thymeleaf变量渲染全解析:从基础到高阶实践
Thymeleaf作为SpringBoot官方推荐的模板引擎,其核心价值在于将动态数据无缝注入静态HTML模板。本文将从基础语法到复杂场景,深入剖析Thymeleaf对各种类型变量的渲染机制。 一、环境搭建与基础配置 依赖注入 在pom.xml中引入核心依赖:<dependency><groupId>org.s…...
【verilog】Verilog 工程规范编码模板
这一套【Verilog 工程规范编码模板】,适合写清晰、可维护、可综合的 RTL 代码,适用于 FPGA/ASIC 开发: 📘 Verilog 工程级编码规范模板 1️⃣ 模块结构规范 module my_module #(parameter WIDTH 8 // 模块参数 )(input wire c…...
satoken的奇奇怪怪的错误
发了 /user/getBrowseDetail和/user/getResponDetail,但为什么进入handle里面有三次?且第一次的handle类型是AbstractHandleMapping$PreFlightHttpRequestHandlerxxx,这一次进来的时候flag为false,StpUtils.checkLogin抛出了异常 第二次进来的…...
使用prometheus-operator部署prometheus服务,并对外提供访问
先决条件: 已经部署好k8s #这里我使用的版本是1.28.12 [rootprometheus-operator /zpf/prometheus/kube-prometheus/manifests]$kubectl version Client Version: v1.28.12 Kustomize Version: v5.0.4-0.20230601165947-6ce0bf390ce3 Server Version: v1.28.12安装git服务 #安…...
FPGA阵列
FPGA(现场可编程门阵列)阵列是由多个 FPGA 芯片组成的集合,通过特定的架构和互联方式协同工作,以实现强大的计算和处理能力。以下是关于 FPGA 阵列的详细介绍: 基本原理 FPGA 是一种可重构的集成电路,内部…...
Oracle补丁安装工具opatch更新报错处理
今日,在进行Oracle补丁升级更新opatch工具包后,执行opatch命令出现了如下报错: [oracles203116 ~]$ opatch version /u01/product/oracle/12.1.0/db_1/OPatch/opatch: line 839: [: too many arguments /u01/product/oracle/12.1.0/db_1/O…...
前端笔记-html+css测试2
HTML & CSS 能力测试卷 选择题(每题2分,共20分) 下列哪个HTML5标签用于定义文档的导航链接? A) <nav> B) <navigate> C) <navbar> D) <navigation> CSS中哪个属性用于设置元素的透明度?…...
Visual Studio C++ 常用配置变量表
前言 visual studio中常用配置变量表 帮助你快速查阅,复制粘贴嘎嘎方便! 附上美图!! 一、解决方案 & 项目路径 变量含义示例(典型用法)$(SolutionDir)解决方案文件所在目录(末尾带\)$(S…...
论文阅读VACE: All-in-One Video Creation and Editing
code:https://github.com/ali-vilab/VACE 核心 单个模型同时处理多种视频生成和视频编辑任务通过VCU(视频条件单元)进行实现 方法 视频任务 所有的视频相关任务可以分为4类 文本生视频 参考图片生视频 视频生视频 视频mask生视频 VCU …...
【Python Cookbook】迭代器与生成器(一)
迭代器与生成器(一) 1.手动遍历迭代器2.代理迭代3.使用生成器创建新的迭代模式4.实现迭代器协议 1.手动遍历迭代器 你想遍历一个可迭代对象中的所有元素,但是却不想使用 for 循环。 为了手动的遍历可迭代对象,使用 next() 函数并…...
Qwen2.5-VL视觉大语言模型复现过程,没碰到什么坑
视频讲解:Qwen2.5-VL视觉大语言模型复现过程,没碰到什么坑_哔哩哔哩_bilibili Qwen2.5-VL视觉大语言模型复现过程,没碰到什么坑 今天复现下Qwen2.5-VL玩玩 https://github.com/QwenLM/Qwen2.5-VL 创建conda环境,实测22.04&#x…...
LVGL填充函数
lvgl填充函数的位置: static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) {LCD_Color_Fill(area->x1,area->y1,area->x2,area->y2,(u16*)color_p);lv_disp_flush_ready(disp_drv); }填充函数的具体内容…...
关于 传感器 的详细解析,涵盖定义、分类、工作原理、常见类型、应用领域、技术挑战及未来趋势,结合实例帮助理解其核心概念
以下是关于 传感器 的详细解析,涵盖定义、分类、工作原理、常见类型、应用领域、技术挑战及未来趋势,结合实例帮助理解其核心概念: 一、传感器的定义与核心功能 1. 定义 传感器(Sensor)是一种能够将物理量ÿ…...
回归,git 分支开发操作命令
核心分支说明 主分支(master/production)存放随时可部署到生产环境的稳定代码,仅接受通过测试的合并请求。 开发分支(develop)集成所有功能开发的稳定版本,日常开发的基础分支,从该分支创建特性…...
指形铣刀的结构
指形铣刀,作为机械加工领域中一种至关重要的切削工具,其主要结构类型多样且各具特色,深入学习这些类型对于提升加工效率与精度至关重要。 首先,我们来看看最基本的直柄指形铣刀。这种铣刀的设计简洁明了,其柄部为直线…...
【verilog】always @(*) 是Verilog 中写组合逻辑
always (*) 是 Verilog 中写组合逻辑(combinational logic) 的标准写法,下面讲解含义、作用、以及为什么这么写。 🌟 什么是 always (*)? always (*) begin// 组合逻辑 end它的意思是: “只要块中用到的任…...
【IC】STA计算
这张图很好,把STA的方法展示的很清楚! 时序分析在每个设计阶段都是必不可少的,以便在现代 IC 设计中实现时序收敛。除了准确性之外,全芯片分析的效率和可扩展性也尤为重要。因此,门级静态时序分析 (STA&am…...
Linux 常用命令总结
Linux 常用命令总结(全面版) Linux 命令行是系统管理和开发的核心工具,掌握常用命令可以极大提升效率。本文全面总结 Linux 常用命令,涵盖文件操作、进程管理、网络管理、系统监控、用户管理、软件安装等多个方面,适合…...
Muduo网络库实现 [十四] - HttpResponse模块
目录 设计思路 类的设计 模块的实现 公有接口 疑问点 设计思路 这个模块和HttpRequest一样,主要就是存储http响应的要素,但是其实真正需要设置存储的要素会比http请求少,首先,要存储http的版本号,我们最终使用的是…...
2025年CNG 汽车加气站操作工考试真题练习
CNG 汽车加气站操作工考试真题练习: 一、单选题 1、CNG 加气站的核心设备是( )。 A. 压缩机 B. 储气瓶组 C. 加气机 D. 脱水装置 答案:A 解析:压缩机是 CNG 加气站的核心设备,其作用是将天然气压缩…...
B端网站建设,怎样平衡功能与美观,满足企业多元需求?
在当今数字化时代,B端网站不仅是企业展示自身形象和产品的重要窗口,更是实现业务转化和客户关系维护的关键平台。然而,B端网站建设面临着功能需求复杂与美观设计之间的平衡问题。如何在满足企业多元需求的同时,打造一个既实用又美…...
PTA:模拟EXCEL排序
Excel可以对一组纪录按任意指定列排序。现请编写程序实现类似功能。 输入格式: 输入的第一行包含两个正整数 n (≤105) 和 c,其中 n 是纪录的条数,c 是指定排序的列号。之后有 n 行,每行包含一条学生纪录。每条学生纪录由学号(6…...
Edge浏览器安卓版流畅度与广告拦截功能评测【不卡还净】
安卓设备上使用浏览器的体验,很大程度取决于两个方面。一个是滑动和页面切换时的反应速度,另一个是广告干扰的多少。Edge浏览器的安卓版本在这两方面的表现比较稳定,适合日常使用和内容浏览。 先看流畅度。Edge在中端和高端机型上启动速度快&…...
Qt 核心库总结
Qt 核心库(QtCore) QtCore 是 Qt 框架的基础模块,提供非图形界面的核心功能,是所有 Qt 应用程序的基石。它包含事件循环、信号与槽、线程管理、文件操作、字符串处理等功能,适用于 GUI 和非 GUI 应用程序。本文将从入…...
四大wordpress模板站
WP汉主题 WP汉主题是一个专注于提供高质量WordPress中文主题的平台。它为中文用户提供了丰富的WordPress主题选择,包括但不限于企业网站模板、外贸建站模板等。WP汉主题致力于帮助用户轻松搭建专业的中文网站,无论是企业官网还是个人博客,都…...
Linux之 grep、find、ls、wc 命令
Linux之 grep、find、ls、wc 命令 “ 在 Linux 世界中,命令行是不可或缺的一部分,而掌握一些常用的命令可以帮助你更有效率地管理文件和系统。本文将为你介绍四個基礎而强大的 Linux 命令:grep、find、ls 和 wc,带你开启高效文件…...
SFC的含义
SFC 即 Single File Component,也就是单文件组件,在现代前端开发尤其是 Vue.js 框架中被广泛应用。下面将从概念、结构、优势、工作原理和应用场景几个方面详细介绍 SFC。 概念 单文件组件是一种将一个组件的模板(HTML)、逻辑&a…...
Qt 性能优化总结
Qt 性能优化总结 本文简单解析 Qt 应用程序的性能优化策略,涵盖 GUI 渲染、内存管理、信号与槽、QML 性能等核心领域,并通过具体示例展示优化效果。 1. Qt 性能优化简介 性能优化目标是减少资源消耗(如 CPU、内存、GPU)、提高响…...
亚马逊关键字搜索数据通过 Product Advertising API 来获取
亚马逊关键字搜索数据主要通过 Product Advertising API 来获取。 以下是使用该接口进行关键字搜索的一般步骤: (测试示例) 注册开发者账号:访问亚马逊开发者中心,完成三方供应商注册并同意相关开发者协议࿰…...
现代C++的范式演进与工程实践深度解析(本文序号不知道怎么整的,有点问题)
引言:C++的复兴时代 在经历了"已死语言"的质疑后,现代C++正迎来前所未有的复兴。据2024年TIOBE指数显示,C++以8.33%的占比稳居第三,较2020年上升2.1个百分点。这种复兴并非偶然——随着C++20标准的全面落地和C++23特性的逐步实现,这门已有40年历史的语言正在系…...