当前位置: 首页 > news >正文

CS144 Lab 6 实战记录:构建 IP 路由器

1 实验背景与目标

在 CS144 的 Lab 6 中,我们需要在之前实现的 NetworkInterface(Lab 5)基础上构建一个完整的 IP 路由器。路由器的主要任务是根据路由表将接收到的 IP 数据报转发到正确的网络接口,并发送给正确的下一跳(next hop)。

一个路由器拥有多个网络接口,可以在任何一个接口上接收 Internet 数据报。路由器的主要职责是根据路由表确定两件事:

  • 应该使用哪个出站接口(interface)发送数据报
  • 数据报的下一跳(next hop)IP 地址是什么

与前几个实验不同,IP 路由器的实现不需要了解 TCP、ARP 或以太网的细节,只需专注于 IP 层的转发逻辑。

2 路由器工作原理

2.1 路由器功能概述

IP 路由器主要完成两个关键功能:

  1. 维护路由表:存储一系列路由规则,每条规则包含网络前缀、前缀长度、下一跳信息和出站接口编号
  2. 转发数据报:根据路由表中的规则,将每个接收到的数据报转发到正确的出站接口和下一跳地址
路由表查询
(最长前缀匹配)
Internet数据报
路由器
转发决策
网络接口1
网络接口2
网络接口n
下一跳1
下一跳2
下一跳n

2.2 最长前缀匹配原则

路由器使用最长前缀匹配(Longest Prefix Match)算法来选择最佳路由。这意味着当多个路由规则匹配一个目标 IP 地址时,路由器会选择前缀长度最长的那个规则。这样可以实现更精确的路由控制。例如,对于目标 IP 地址 172.16.10.3,可能匹配的规则有 172.16.0.0/16172.16.10.0/24,路由器会选择前缀长度为 24 的规则,因为它提供了更精确的匹配。

接收数据报
检查目标IP地址
在路由表中查找匹配项
有多个匹配项?
选择前缀长度最长的匹配项
有一个匹配项?
使用该匹配项
丢弃数据报
确定出站接口和下一跳
TTL减1
TTL大于0?
通过选定接口发送到下一跳
丢弃数据报

3 路由器实现

3.1 数据结构设计

将路由表按前缀长度(1-32)分成32个组,方便从长到短进行最长前缀匹配。每个前缀长度组内使用哈希表存储,表示匹配前缀与路由项的映射关系。

struct RouteEntry {size_t interface_num {};      // 出站接口编号std::optional<Address> next_hop {}; // 下一跳地址(如果有)
};// 路由表,按前缀长度分组(最多32个组,对应IPv4地址的32位,逆序表示。例如下标为0代表前缀长度32)
std::array<std::unordered_map<uint32_t, RouteEntry>, 32> routing_table_ {};

3.2 添加路由条目

add_route方法向路由表添加一条新的路由规则,具体处理逻辑:

  1. 前缀计算:使用右移操作获取有效前缀位,例如:对于 192.168.1.0/24,右移 (32-24) = 8 位,保留高 24 位作为匹配前缀。需要特别处理前缀长度为 0 的默认路由,避免右移 32 位导致的未定义行为
  2. 路由条目存储:将路由条目存入对应前缀长度的哈希表中,键是处理后的前缀,值是路由条目信息
void Router::add_route(const uint32_t route_prefix,const uint8_t prefix_length,const optional<Address> next_hop,const size_t interface_num) {cerr << "DEBUG: adding route " << Address::from_ipv4_numeric(route_prefix).ip() << "/"<< static_cast<int>(prefix_length) << " => " << (next_hop.has_value() ? next_hop->ip() : "(direct)")<< " on interface " << interface_num << "\n";// 截取route_prefix的前prefix_length位作为有效前缀uint32_t masked_prefix = (prefix_length == 0) ? 0 : (route_prefix >> (32 - prefix_length));// 插入到对应前缀长度的路由表中routing_table_[prefix_length][masked_prefix] = { interface_num, next_hop };
}

3.3 路由匹配查找

match 方法实现最长前缀匹配算法,为每个数据报找到最佳路由:

flowchart TDA[开始匹配] --> B[从前缀长度31开始]B --> C[计算目标IP地址的前len位]C --> D{前缀长度组中\n有匹配项?}D -->|是| E[返回匹配的路由条目]D -->|否| F[前缀长度减1]F --> G{前缀长度≥0?}G -->|是| CG -->|否| H[返回无匹配]
optional<Router::RouteEntry> Router::match(uint32_t dst_addr) const noexcept {for (int len = 31; len >= 0; --len) {uint32_t masked = (len == 0) ? 0 : (dst_addr >> (32 - len));const auto& table = routing_table_[len];auto it = table.find(masked);if (it != table.end()) {return it->second;}}return nullopt;
}

3.4 数据报转发处理

route 方法是路由器的核心功能,负责处理所有接口收到的数据报并进行转发。

网络接口 路由器 最长前缀匹配 转发逻辑 遍历所有接口 获取接收到的数据报队列 检查TTL值 丢弃数据报 TTL减1并重新计算校验和 查找最长前缀匹配路由 返回匹配的路由条目 确定目标地址和出站接口 通过对应接口发送数据报 丢弃数据报 alt [有匹配路由] [无匹配路由] alt [TTL ≤ 1] [TTL > 1] loop [对每个数据报] 网络接口 路由器 最长前缀匹配 转发逻辑
void Router::route() {for (const auto& interface : interfaces_) {auto& datagrams_received = interface->datagrams_received();// 处理所有收到的数据报while (!datagrams_received.empty()) {InternetDatagram datagram = move(datagrams_received.front());datagrams_received.pop();// TTL ≤ 1表示不能再转发,直接丢弃if (datagram.header.ttl <= 1) {continue;}// TTL减1并重新计算校验和datagram.header.ttl -= 1;datagram.header.compute_checksum();// 使用最长前缀匹配查找路由条目auto routeEntry = match(datagram.header.dst);if (!routeEntry.has_value()) {continue;}// 如果没有指定下一跳,则直接发送到目标IPAddress target = routeEntry->next_hop.value_or(Address::from_ipv4_numeric(datagram.header.dst));// 通过对应接口发送数据报interfaces_[routeEntry->interface_num]->send_datagram(datagram, target);}}
}

4 调试记录

  1. 最初在计算掩码后的前缀时,使用了按位与操作,但这种方法对于可变长度前缀处理起来比较复杂。改用右移操作后,处理变得更简单高效。

  2. 最初的实现中,先执行路由匹配再检查TTL,这导致一些应该被丢弃的数据报被错误处理。修正为先检查TTL再进行后续处理。

  3. 处理前缀长度为0的默认路由时需要特殊处理,确保将掩码设置为0而不是尝试右移32位(这会导致未定义行为)。

    image-20250424213846855

5 代码仓库

项目代码已上传至GitHub:https://github.com/HeZephyr/minnow

相关文章:

CS144 Lab 6 实战记录:构建 IP 路由器

1 实验背景与目标 在 CS144 的 Lab 6 中&#xff0c;我们需要在之前实现的 NetworkInterface&#xff08;Lab 5&#xff09;基础上构建一个完整的 IP 路由器。路由器的主要任务是根据路由表将接收到的 IP 数据报转发到正确的网络接口&#xff0c;并发送给正确的下一跳&#xf…...

AI与智能能源管理:如何通过AI优化能源分配和消耗?

引言&#xff1a;能源管理面临的新挑战 在“双碳”目标持续推进的背景下&#xff0c;能源管理已经不再是简单的节电节水问题&#xff0c;而是关乎可持续发展和企业长期竞争力的核心议题。无论是工业园区、写字楼&#xff0c;还是家庭用户&#xff0c;能源的使用正在变得越来越复…...

【蓝桥杯】产值调整

产值调整 题目描述 偏远的小镇上&#xff0c;三兄弟共同经营着一家小型矿业公司“兄弟矿业”。公司旗下有三座矿山&#xff1a;金矿、银矿和铜矿&#xff0c;它们的初始产值分别用非负整数 A A A、 B B B 和 C C C 表示。这些矿山的产出是小镇经济的核心&#xff0c;支撑着…...

使用Next.js构建单页面React应用

最近遇到一个问题 突然要一个单页面的项目 用惯了Next.js 而 create-react-app 又不推荐且不灵活 最终找发现Nextjs也支持单页面应用 以下是使用Next.js构建单页面React应用过程 1 正常创建项目 (我选择的是Pages Router 而非 AppRoute) 2 修改配置文件 next.config.ts impor…...

Python字符串三剑客:len()、split()、join()深度解析

目录 一、len()&#xff1a;字符串的"测谎仪" 二、split()&#xff1a;字符串的"解剖刀" 参数解析&#xff1a; 实战场景&#xff1a; 三、join()&#xff1a;字符串的"缝合怪" 性能优势&#xff1a; 实战案例&#xff1a; 高级技巧&…...

大模型是如何生成内容的?

大模型&#xff08;如 GPT、Claude、LLaMA 等&#xff09;生成内容的过程&#xff0c;其实就是一个 逐词预测上下文推理 的过程。我们可以把它想象成一个“超级自完成引擎”&#xff1a;每一步都在问自己—— “在目前上下文下&#xff0c;最合理的下一个词是什么&#xff1f;”…...

Python元组全面解析:从基础到高级应用指南

一、元组基础概念与核心特性 1.1 元组的本质定义 元组&#xff08;Tuple&#xff09;是Python中重要的不可变序列类型&#xff0c;由多个元素组成的有序集合。其核心特性表现在&#xff1a; 元素按插入顺序存储&#xff0c;支持索引访问所有元素存储在连续内存空间&#xff…...

Docker部署DeepSeek常见问题及解决方案

在使用Docker部署DeepSeek的过程中,许多开发者可能会遇到一些常见问题。本文整理了几个高频问题及其解决方案,帮助大家更顺利地完成部署。 镜像拉取失败 问题现象 执行 docker pull 命令时,提示超时或镜像不存在。 可能原因 1. 网络环境不稳定,导致连接Docker Hub失败…...

身份证实名认证接口数字时代的信任基石-node.js实名认证集成

在互联网深度渗透生活的当下&#xff0c;从线上购物、社交娱乐到金融理财、政务办理&#xff0c;每一次指尖的触碰都在虚拟世界中留下痕迹。身份证实名认证作为连接现实身份与网络身份的桥梁&#xff0c;正以其不可替代的作用&#xff0c;重塑着数字时代的信任体系。它不仅是保…...

多维时序 | LightGBM多变量时序预测(Matlab完整源码和数据,适合基础小白研究)

多维时序 | LightGBM多变量时序预测&#xff08;Matlab完整源码和数据&#xff0c;适合基础小白研究&#xff09; 目录 多维时序 | LightGBM多变量时序预测&#xff08;Matlab完整源码和数据&#xff0c;适合基础小白研究&#xff09;效果一览基本介绍程序设计参考资料 效果一览…...

强化学习(Reinforcement Learning, RL)和深度学习(Deep Learning, DL)

强化学习&#xff08;Reinforcement Learning, RL&#xff09;和深度学习&#xff08;Deep Learning, DL&#xff09;是人工智能领域两个重要的研究方向&#xff0c;虽然二者可以结合&#xff08;如深度强化学习&#xff09;&#xff0c;但其核心思想、目标和应用场景存在本质区…...

图论---Prim堆优化(稀疏图)

题目通常会提示数据范围&#xff1a; 若 V ≤ 500&#xff0c;两种方法均可&#xff08;朴素Prim更稳&#xff09;。 若 V ≤ 1e5&#xff0c;必须用优先队列Prim vector 存图。 #include <iostream> #include <vector> #include <queue> #include <…...

【优秀三方库研读】【C++基础知识】odygrd/quill -- 折叠表达式

compute_encoded_size_and_cache_string_lengths 方法中这段代码是一个C的折叠表达式&#xff08;fold expression&#xff09;的应用&#xff0c;用于计算多个参数编码后的总大小。下面我将详细解释这段代码的每个部分&#xff0c;并说明为什么这样写。 代码如下&#xff1a; …...

优化Nginx的下载功能

缘起&#xff1a; 我购置了一台阿里云ECS&#xff0c;其EIP带宽3m/s&#xff0c;但是在其上的作为下载文件的服务器nginx提供的下载速度仅有几百KB。 分析&#xff1a; 既然没有达到带宽瓶颈&#xff0c;肯定存在优化的空间。浮现脑海的想法&#xff0c;nginx没有进行最佳配置…...

Vue3集成浏览器API实时语音识别

效果示例 用法 <!-- 浏览器语音识别 --> <BrowserSpeechRecognitionModal v-if"showModal" :isOpen"showModal" close"showModal false" confirm"handleRecognitionResult" />const showModal ref(false); const input…...

Python3 基础:函数定义与调用

Python3 基础&#xff1a;函数定义与调用 什么是函数&#xff1f;一、函数的定义二、函数的调用三、函数参数3.1位置参数3.2关键字参数3.3默认参数值3.4可变数量的参数args&#xff1a;接收任意数量的位置参数**kwargs&#xff1a;接收任意数量的关键字参数 3.5 综合使用各种参…...

Vue 2 的响应式 API 和 Vue 3 的组合式 API 的详细对比,从核心机制、使用方式、代码示例及优缺点展开

以下是 Vue 2 的响应式 API 和 Vue 3 的组合式 API 的详细对比&#xff0c;从核心机制、使用方式、代码示例及优缺点展开&#xff1a; 1. Vue 2 的响应式 API 核心机制 基于 Object.defineProperty&#xff1a; 通过劫持对象的 getter 和 setter 实现数据变化追踪。限制&…...

修改了Element UI中组件的样式,打包后样式丢失

修改了Element UI中组件的样式&#xff0c;在本地运行没有问题&#xff0c;但是打包到线上发现样式丢失&#xff08;样式全部不生效、或者有一部分生效&#xff0c;一部分不生效&#xff09;&#xff0c;问题在于css的加载顺序导致代码编译后样式被覆盖了&#xff0c; 解决办法…...

大模型工业化元年:GPT-5开启通用AI新纪元,中国技术如何破局?

过去一周&#xff0c;AI领域的焦点无疑是OpenAI发布的GPT-5预览版&#xff0c;以及全球大模型技术从实验室迈向工业化的关键转折。这场变革不仅标志着通用人工智能&#xff08;AGI&#xff09;的进一步逼近&#xff0c;更掀起了全球产业链的竞争与反思。本文将从技术突破、产业…...

离线电脑安装python包

离线电脑安装python第三方库 在联网电脑上下载Python包 使用pip安装所需的包&#xff0c;例如 pip install requests numpy导出已安装的包列表 pip freeze > requirements.txt根据requirements.txt下载包及其所有依赖项到指定目录&#xff1a; pip download -r require…...

【Unity AR开发插件】一、高效热更新:Unity AR 插件结合 HybridCLR 与 ARFoundation 的开源仓库分享

摘要 本篇博客详细介绍了我基于 HybridCLR 与 AR Foundation 的 Unity AR 开发插件&#xff0c;旨在为开发者提供高效的跨平台热更新方案。文章从背景与动机出发&#xff0c;覆盖一键安装工具、环境配置、热更新数据制作与示例程序运行等核心模块&#xff0c;并展示代码结构与使…...

深入浅出学会函数(下)

5. return语句 在函数的设计中&#xff0c;函数中经常会出现return语句&#xff0c;这里讲一下return语句使用的注意事项。 return 后面可以是一个数值&#xff0c;也可以是一个表达式&#xff0c;如果是表达式先执行表达式&#xff0c;再返回表达式的结果。return 后面也可以…...

架构-软件工程

一、软件过程模型&#xff08;核心高频考点&#xff09; 1. 瀑布模型 知识点&#xff1a;严格分阶段&#xff08;需求→设计→编码→测试→维护&#xff09;&#xff0c;前一阶段输出是后一阶段输入&#xff0c;阶段间因果紧密&#xff0c;适合需求明确且稳定的项目。缺点&am…...

Redis 及其在系统设计中的作用

什么是Redis Redis 是一个开源的内存数据结构存储系统&#xff0c;可用作数据库、缓存和消息代理。它因其快速的性能、灵活性和易用性而得到广泛应用。 Redis 数据存储类型 Redis 允许开发人员以各种数据结构&#xff08;例如字符串、位图、位域、哈希、列表、集合、有序集合…...

运维打铁:Centos 7 使用yum安装 mysql5.7

文章目录 一、安装前信息说明二、安装步骤1. 下载并安装官网 RPM 安装包2. 修改配置文件 /etc/my.cnf3. 创建 MySQL 数据相关目录并授权4. 启动 MySQL 服务 三、修改数据库访问密码1. 修改配置文件 /etc/my.cnf2. 重启 MySQL 服务3. 登录数据库并修改密码4. 恢复配置文件并重启…...

第二章:MCP服务器分类

Chapter 2: MCP服务器分类 &#x1f31f; 从上一章到本章 在第一章&#xff1a;Model Context Protocol (MCP)中&#xff0c;我们学习了如何通过MCP让LLM安全访问文件系统。现在&#xff0c;让我们想象一个更复杂的需求&#xff1a;假设你需要让LLM同时处理文件、查询数据库、…...

遨游三防|30200mAh、双露营灯三防平板,见证堆料天花板

在工业4.0与智能化转型的浪潮中&#xff0c;专业设备对性能、防护及场景适应性的要求日益严苛。遨游通讯作为国家级高新技术企业&#xff0c;依托“危、急、特”场景的深耕经验&#xff0c;推出的旗舰级产品AORO-P300三防平板&#xff0c;以30200mAh超大容量电池、双露营灯设计…...

OFDM 信道表示(3)

上节我们令得到频域相关系数与PDP是一对傅里叶变换对。这次我们令即只考虑同一个RE上随时间变化得过程。 为接收信号自相关函数&#xff0c;令即为上式 所以可得Doppler 功率谱和子相关函数一对傅里叶变换对。 上面给出多径DPL信道接受信号表示&#xff0c;其中为t时间多径时延…...

MongoDB副本集搭建与核心机制

一、节点架构解析 1.1 节点角色分工 主节点&#xff08;Primary&#xff09; 唯一写入口&#xff1a;处理所有写操作&#xff08;插入/更新/删除&#xff09; Oplog生成器&#xff1a;记录操作日志到local.oplog.rs集合 同步中枢&#xff1a;向所有从节点推送oplog变更 典型…...

深度学习-数值稳定性和模型初始化

到目前为止&#xff0c;我们实现的每个模型都是根据某个预先制定的分布来初始化模型的参数&#xff0c;有人会认为初始化方案时理所当然的&#xff0c;忽略了如何做出这些选择的细节&#xff0c;甚至有人可能会觉得&#xff0c;初始化方案的选择并不是特别重要&#xff0c;实际…...

详解Linux中的定时任务管理工具crond

在 Linux 容器环境中&#xff0c;/etc/cron.d/ 目录可能不存在&#xff0c;特别是在精简的容器镜像&#xff08;如 Alpine、BusyBox 或某些定制化的镜像&#xff09;中。这是因为容器通常追求轻量级&#xff0c;默认不包含完整的 cron 系统&#xff08;如 cronie 或 vixie-cron…...

【element plus】解决报错error:ResizeObserver loop limit exceeded的问题

当我们在使用element plus框架时&#xff0c;有时会遇到屏幕突然变暗&#xff0c;然后来一句莫名其妙的报错ResizeObserver loop limit exceeded&#xff0c;其实这是因为改变屏幕大小时el-table导致的报错 网上给出了几种解决方案&#xff0c;我试了其中两种可以实现 方案一&…...

GD32E23x flash作为静态存储的读写操作

目录 一、前言 二、GD32E23x flash扇区地址划分 三、GD32E23x 固件库下载 四、GD32E23x falsh擦写操作函数封装 五&#xff0c;引用示例 一、前言 在只有芯片没有外部存储时需要存储一些配置信息&#xff0c;使用flash进行存储是很好的选择了&#xff0c;在GD32E23x中以flash…...

空闲列表:回收和再利用

空闲列表&#xff1a;回收和再利用 手动与自动内存管理 手动管理&#xff1a;程序员需要明确地分配和释放内存。自动管理&#xff1a;例如使用垃圾收集器(GC)&#xff0c;它能够自动检测并回收未使用的对象&#xff0c;不需要程序员干预。 对于某些数据结构如B树&#xff0c;…...

功能脑网络较新的方法[和ai讨论的方向和学习资源]

文章目录 前言和回顾代码实现ai 提问大脑连通性分析方法扩展与分类指南一、现有方法的补充与分类1. 补充的其他连通性方法2. 分类框架 二、近年来的新方法&#xff08;2019年后&#xff09;1. 相位动力学扩展2. 信息论与复杂度3. 基于图论与网络科学4. 动态系统与因果推断 三、…...

【MongoDB + Spark】 技术问题汇总与解决方案笔记

场景背景 最近练手项目&#xff1a;Spark 结合 MongoDB 构建商品推荐系统的过程中&#xff0c;过程中出现多种环境配置与兼容性问题&#xff0c;主要涉及 MongoDB 连接、版本兼容性、Casbah 驱动使用问题等。汇总调试过程中遇到的常见错误及其解决方案&#xff0c;供参考复用。…...

给git配置SSH(github,gitee)

更多个人笔记&#xff1a;&#xff08;仅供参考&#xff0c;非盈利&#xff09; gitee&#xff1a; https://gitee.com/harryhack/it_note github&#xff1a; https://github.com/ZHLOVEYY/IT_note 本文基于mac&#xff0c;linux和win可以参考 个人同时配置gitee和github的ss…...

Linux基础使用-笔记

1. 文件和目录操作 查看当前目录&#xff1a;pwd 命令用于显示当前工作目录的完整路径。 pwd切换目录&#xff1a;cd 命令用于切换工作目录。 # 切换到指定目录 cd /home/user/Documents # 切换到上一级目录 cd .. # 切换到用户主目录 cd ~列出目录内容&#xff1a;ls 命令用…...

什么是Maven

Maven的概念 Maven是一个一键式的自动化的构建工具。Maven 是 Apache 软件基金会组织维护的一款自动化构建工具&#xff0c;专注服务于Java 平台的项目构建和依赖管理。Maven 这个单词的本意是&#xff1a;专家&#xff0c;内行。Maven 是目前最流行的自动化构建工具&#xff0…...

DNS主从同步及解析

DNS 域名解析原理 域名系统的层次结构 &#xff1a;DNS 采用分层树状结构&#xff0c;顶级域名&#xff08;如.com、.org、.net 等&#xff09;位于顶层&#xff0c;下面是二级域名、三级域名等。例如&#xff0c;在域名 “www.example.com” 中&#xff0c;“com” 是顶级域名…...

Git 的基本概念和使用方式

Git 是一种分布式版本控制系统,广泛用于跟踪文件的变化和协作开发项目。以下是 Git 的基本概念和使用方式: 仓库(Repository):Git 用来存储项目文件和历史记录的地方。可以是本地仓库(Local Repository)或远程仓库(Remote Repository)。 工作区(Working Directory):…...

【C++】二叉树进阶面试题

根据二叉树创建字符串 重点是要注意括号省略问题&#xff0c;分为以下情况&#xff1a; 1.左字树为空&#xff0c;右子树不为空&#xff0c;左边括号保留 2.左右子树都为空&#xff0c;括号都不保留 3。左子树不为空&#xff0c;右子树为空&#xff0c;右边括号不保留 如果根节…...

时序数据库IoTDB构建的能源电力解决方案

随着能源格局的快速变化与“双碳”战略的逐步践行&#xff0c;电力系统的绿色低碳转型已成为重要发展趋势。在这一背景下&#xff0c;数字化、智能化技术正逐步扩大在新型电力系统发电侧、电网侧、储能侧的应用&#xff0c;以推动传统电力发输配用向全面感知、双向互动、智能高…...

【KWDB 创作者计划】_上位机知识篇---Github

文章目录 前言1. GitHub 核心功能(1) 代码托管(Git 仓库)存储代码版本控制代码浏览(2) 协作开发Pull RequestlssuesProjectsDiscussions(3) 自动化与 CI/CDGitHub ActionsGitHub PagesDependabot(4) 社区与开源ForkStarWatchSponsor2. GitHub 基本使用方法(1) 创建仓库(Repo…...

vxe-table封装表头

待补充使用说明&#xff0c;但是可以用 一.效果二.封装MyTable.vue1.封装index.vue2.日期选择筛选3.输入筛选4.下拉筛选5.多选筛选6.远程多选筛选7.远程单选筛选 三、页面使用1.具体页面使用2./utils/filter.js 注意&#xff1a;需要使用jsx、vxe-table、element-plus 一.效果 …...

力扣hot100 91-100记录

91-100 &#xff08;动态规划&#xff09; class Solution { public:int uniquePaths(int m, int n) {vector<vector<int>> f(m, vector<int>(n, 1));for(int i 1; i < m; i){for(int j 1; j < n; j){f[i][j] f[i-1][j] f[i][j-1];} }return f[…...

SpringMVC处理请求映射路径和接收参数

目录 springmvc处理请求映射路径 案例&#xff1a;访问 OrderController类的pirntUser方法报错&#xff1a;java.lang.IllegalStateException&#xff1a;映射不明确 核心错误信息 springmvc接收参数 一 &#xff0c;常见的字符串和数字类型的参数接收方式 1.1 请求路径的…...

ESP32上C语言实现JSON对象的创建和解析

在ESP32上使用C语言实现JSON对象的创建和解析&#xff0c;同样可以借助cJSON库。ESP-IDF&#xff08;Espressif IoT Development Framework&#xff09;本身已经集成了cJSON库&#xff0c;你可以直接使用。以下是详细的步骤和示例代码。 1. 创建一个新的ESP-IDF项目 首先&…...

关于Qt对Html/CSS的支持

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、原生控件二、QtWebEngine总结 前言 最近遇到了一些问题需要使用Qt加载Html发现一些特性不能使用&#xff0c;估计很多人也和我一样遇到这种情况。需要说明…...

Python 读取 txt 文件详解 with ... open()

文章目录 1 概述1.1 注意事项1.2 模式说明1.3 文件准备 2 读文件2.1 读取整个文件2.2 逐行读取2.3 读取所有行到列表 3 写文件3.1 覆盖写入3.2 追加写入3.3 写入多行 4 实用技巧4.1 检查文件是否存在4.2 异常处理 1 概述 1.1 注意事项 文件编码&#xff1a;建议指定编码&…...