<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/scripts/pretty-feed-v3.xsl" type="text/xsl"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:h="http://www.w3.org/TR/html4/"><channel><title>Frank&apos;s Lab</title><description>Building with code, agents, and curiosity</description><link>https://frank-whw.com</link><item><title>重装 x64 版 Edge WebView2 的心酸</title><link>https://frank-whw.com/blog/articles/fixed-version-webview2</link><guid isPermaLink="true">https://frank-whw.com/blog/articles/fixed-version-webview2</guid><description>这篇文章记录了我如何绕过 WebView2 安装器的历史坑，改用 Fixed Version 运行时稳定解决问题。</description><pubDate>Sun, 16 Nov 2025 03:45:41 GMT</pubDate><content:encoded>&lt;h2&gt;问题背景&lt;/h2&gt;
&lt;p&gt;在开发 Dayflow（Tauri + React + Rust）时，执行 &lt;code&gt;npm run tauri dev&lt;/code&gt; 报错，原生窗口无法弹出。&lt;/p&gt;
&lt;p&gt;初步判断是 WebView2 Runtime 的架构不匹配：当前应用需要 x64 版 Edge WebView2 Runtime，但机器上已有的运行时环境可能不是正确的 x64 版本。&lt;/p&gt;
&lt;h2&gt;初始尝试&lt;/h2&gt;
&lt;p&gt;我先从 &lt;code&gt;https://developer.microsoft.com/en-us/microsoft-edge/webview&lt;/code&gt; 下载 Evergreen Bootstrapper，预期它能自动安装匹配架构的 WebView2 Runtime。&lt;/p&gt;
&lt;p&gt;实际结果是安装失败：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Frank-whw/img/main/blog/202511161124360.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;随后我又尝试以管理员身份强制安装，但在对应目录里仍然没有发现预期文件。&lt;/p&gt;
&lt;h2&gt;原因分析&lt;/h2&gt;
&lt;p&gt;机器上原本已经存在 32 位 WebView2，而 Evergreen 安装器在历史行为上存在目录与架构混淆的问题。&lt;/p&gt;
&lt;p&gt;MicrosoftEdge/WebView2Feedback 的 Issue 1044 中提到，Bootstrapper/Standalone Installer 可能会把 x64 和 x86 都安装到：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;%ProgramFiles(x86)%\Microsoft\EdgeWebView\Application
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;后安装的版本可能覆盖前一个版本，最终导致运行时架构异常。&lt;/p&gt;
&lt;p&gt;参考链接：&lt;code&gt;https://github.com/MicrosoftEdge/WebView2Feedback/issues/1044&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Frank-whw/img/main/blog/202511161127210.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;如果要验证 &lt;code&gt;msedgewebview2.exe&lt;/code&gt; 的架构，可以查看 PE 头：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;8664&lt;/code&gt; 表示 x64；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;14C&lt;/code&gt; 表示 x86。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;解决思路&lt;/h2&gt;
&lt;p&gt;最终我放弃了 Bootstrapper，改用 Fixed Version（固定版本）运行时。&lt;/p&gt;
&lt;p&gt;这样做的好处是：不依赖系统已有 WebView2 的注册表和默认安装路径，而是把运行时解压到一个明确的自定义目录，再通过环境变量告诉应用去哪里找 &lt;code&gt;msedgewebview2.exe&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;需要设置的关键环境变量是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;WEBVIEW2_BROWSER_EXECUTABLE_FOLDER&lt;/code&gt;：指向包含 &lt;code&gt;msedgewebview2.exe&lt;/code&gt; 的解压目录；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS&lt;/code&gt;：可选，用于传递额外启动参数，例如禁用 GPU、打开日志，排除显卡驱动问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;固定版本安装与配置脚本&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;$cabPath = &quot;...\Microsoft.WebView2.FixedVersionRuntime.142.0.3595.80.x64.cab&quot;
$version = &quot;142.0.3595.80&quot;
$destRoot = &quot;C:\WebView2Fixed\x64&quot;
$dest = Join-Path $destRoot $version

New-Item -ItemType Directory -Force -Path $dest | Out-Null
Write-Host &quot;解压到: $dest&quot;
&amp;#x26; expand.exe $cabPath -F:* $dest

$exe = Get-ChildItem -Path $dest -Filter msedgewebview2.exe -Recurse | Select-Object -First 1
if (-not $exe) { Write-Error &quot;解压后未找到 msedgewebview2.exe&quot;; exit 1 }

$env:WEBVIEW2_BROWSER_EXECUTABLE_FOLDER = (Split-Path -Parent $exe.FullName)
$env:WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS = &quot;--disable-gpu --enable-logging --v=1&quot;
Write-Host &quot;WEBVIEW2_BROWSER_EXECUTABLE_FOLDER=$env:WEBVIEW2_BROWSER_EXECUTABLE_FOLDER&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;结果&lt;/h2&gt;
&lt;p&gt;固定版本 WebView2 Runtime 成功解压并可用。通过环境变量显式指定运行时目录后，Tauri 应用可以稳定使用 x64 版 WebView2，不再依赖系统中可能混乱的 Evergreen 安装状态。&lt;/p&gt;
&lt;p&gt;这类问题的关键是不要只相信安装器“应该会装对”。当 x86/x64 架构混在一起时，直接使用 Fixed Version Runtime 反而更可控。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>读《认知觉醒》有感</title><link>https://frank-whw.com/blog/thoughts/cognitive-awakening</link><guid isPermaLink="true">https://frank-whw.com/blog/thoughts/cognitive-awakening</guid><description>这不是一篇书摘，而是一次对焦虑、耐心、复利和行动习惯的集中反思。</description><pubDate>Sat, 15 Nov 2025 13:18:27 GMT</pubDate><content:encoded>&lt;h2&gt;读《认知觉醒》有感&lt;/h2&gt;
&lt;p&gt;这本书我前后读了 20 天。前期多是零散翻阅，最后一两周才真正沉下心读完。&lt;/p&gt;
&lt;p&gt;读得不算慢。一方面，书里很多理论并不晦涩，它们本来就藏在日常经验里；另一方面，它确实很戳我。许多看似“显而易见”的道理，被重新串联之后，反而带来很多新的触动。更重要的是，它真的让我发生了一点改变：如果是以前，我读完一本书大概率不会主动写感悟，但这次我很想把这些触动记下来。&lt;/p&gt;
&lt;p&gt;下面是几个让我感触很深的点，想慢慢梳理：&lt;/p&gt;
&lt;h3&gt;1. 三层脑结构：看懂自己的“决策惯性”&lt;/h3&gt;
&lt;p&gt;书中讲到“本能脑、情绪脑、理智脑”的三层结构。它让我意识到，我们很多决策其实并不是“理智说了算”，反而常常被本能脑和情绪脑牵着走。&lt;/p&gt;
&lt;p&gt;这也解释了为什么我总喜欢为自己的行为和欲望找理由。说到底，人是很擅长自我解释的动物。哪怕理由并不牢靠，也会先编出一套说法，让自己“过得去”。&lt;/p&gt;
&lt;h3&gt;2. 焦虑的根源：我正踩中的“急功近利陷阱”&lt;/h3&gt;
&lt;p&gt;书里说，焦虑源于“想同时做很多事，又想立即看到效果”。这几乎就是在说我。&lt;/p&gt;
&lt;p&gt;不管是专业学习，还是炒币，我都太急了。总盼着一步到位、快速见效，稍微看不到成果就开始慌。耐心早就被“速成期待”磨掉了。现在才懂，这种求快本身就会制造焦虑，也会让我更难沉下心。&lt;/p&gt;
&lt;h3&gt;3. 耐心与复利：等得到“质变的拐点”&lt;/h3&gt;
&lt;p&gt;“延迟满足”和“复利曲线”的关系，刷新了我对耐心的理解。&lt;/p&gt;
&lt;p&gt;以前我总觉得，没耐心是因为毅力差。现在才明白，耐心不是单纯熬时间，而是相信积累到某个临界点之后，事情会发生质变。就像我过去总抱怨“努力没效果”，其实很多时候只是没有等到那个悄悄扎根的阶段，就已经提前放弃了。&lt;/p&gt;
&lt;h3&gt;4. 拉伸区成长：别在舒适区里“假装努力”&lt;/h3&gt;
&lt;p&gt;“真正的成长在拉伸区”这句话，也让我反思自己的状态。&lt;/p&gt;
&lt;p&gt;我平时输入不少，看书、学知识、刷文章都不算少，但输出严重跟不上。写总结、做分享，总能找到理由推脱。说到底，还是害怕跳出“只输入不输出”的舒适区。&lt;/p&gt;
&lt;p&gt;成长本来就该有点痛。只有敢做那些“不愿意但该做”的事，进步才会真的发生。&lt;/p&gt;
&lt;h3&gt;5. 积累的优先级：别做“知识囤积者”&lt;/h3&gt;
&lt;p&gt;书里提到一个排序：改变量 &gt; 行动量 &gt; 思考量 &gt; 学习量。&lt;/p&gt;
&lt;p&gt;这句话一下点醒了我。以前我总以为“学得多就有用”，于是囤了很多课，读了很多书，却很少认真想“学了之后能怎么用”，更别说落实到行动、带来改变。&lt;/p&gt;
&lt;p&gt;现在才懂，没有行动和改变的学习，只是一种看起来很努力的消耗。&lt;/p&gt;
&lt;h3&gt;6. 耐心的本质：有长远目光，才不用硬撑&lt;/h3&gt;
&lt;p&gt;“耐心不是靠毅力硬撑，而是靠长远目光。”这句话彻底扭转了我的认知。&lt;/p&gt;
&lt;p&gt;以前我总逼自己“必须坚持”，结果越逼越累。现在试着换一个角度：比如学专业知识时，不再想着“今天学了明天就能立刻用上”，而是想着“学会以后能解决更大的问题”。这样反而更容易沉下心。&lt;/p&gt;
&lt;p&gt;原来耐心不是硬熬出来的，而是看得更远之后自然长出来的。&lt;/p&gt;
&lt;h3&gt;7. 后娱乐：让大脑适应困难的事&lt;/h3&gt;
&lt;p&gt;“后娱乐”的方法特别实用：先搞定困难的事，再享受娱乐，而不是先放纵，再带着负罪感做事。&lt;/p&gt;
&lt;p&gt;试了几天之后，我发现大脑真的会慢慢适应。比如先写完学习总结再刷手机，慢慢就不觉得“写总结”是负担，甚至能从“搞定困难”里得到成就感。相比之下，那些轻松的娱乐反而没那么有吸引力了。&lt;/p&gt;
&lt;h3&gt;8. 提升思考：抓核心，沉心得&lt;/h3&gt;
&lt;p&gt;书里说，提升思考能力，要不断明确核心困难、提炼心得，再专注于此。这一点和我读这本书的感受很契合。&lt;/p&gt;
&lt;p&gt;以前我思考问题总抓不住重点，遇到问题时经常在细节里打转。现在我会试着先找“最卡壳的核心”：比如写这篇感悟时，先问自己到底哪个点最触动我，再围绕它沉淀经验。这样思考就会更有方向，而不是漫无目的地“瞎想”。&lt;/p&gt;
&lt;h3&gt;9. 动机转移：给“不想做的事”找一个甜动力&lt;/h3&gt;
&lt;p&gt;“动机转移”的思路也很有启发。&lt;/p&gt;
&lt;p&gt;遇到不想做的事，不一定要硬逼自己“必须做”，也可以换一个角度重新寻找动力。比如以前我不想学专业知识，觉得枯燥；现在试着把动机换成“学会它就能解决工作里的具体问题”，行动力就会强很多。&lt;/p&gt;
&lt;p&gt;有些事情不是没意义，只是我还没找到让自己愿意动起来的理由。&lt;/p&gt;
&lt;h3&gt;10. 落地的小习惯：简单但有力量&lt;/h3&gt;
&lt;p&gt;最后是“早起、冥想、运动、阅读”这些具体建议。它们没有复杂的道理，却都是能落地的小抓手。&lt;/p&gt;
&lt;p&gt;我试着每天早起半小时读会儿书，发现早上的专注力确实很好；偶尔加 10 分钟冥想，也能让浮躁的心态安静下来。&lt;/p&gt;
&lt;p&gt;原来提升认知不一定要做什么“大动作”。把这些小事持续做好，就会慢慢产生改变。&lt;/p&gt;
&lt;h2&gt;结语&lt;/h2&gt;
&lt;p&gt;整体读下来，《认知觉醒》不是一本单纯“讲大道理”的书，更像一个帮我看清自己、找到落地方法的朋友。&lt;/p&gt;
&lt;p&gt;那些看似熟悉的观点，被作者点透之后，反而成了能真正改变行为的力量。从“读完不写感悟”到主动记录，从“急功近利”到试着耐心积累，这些小小的变化，或许就是这本书给我最好的礼物。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>AWS EC2 连接异常的技术原因客观分析</title><link>https://frank-whw.com/blog/articles/aws-ec2-network-analysis</link><guid isPermaLink="true">https://frank-whw.com/blog/articles/aws-ec2-network-analysis</guid><description>一次 EC2 连接不稳定排障，被拆解成 DNS、校园网限制和代理转发三层问题来分析。</description><pubDate>Wed, 12 Nov 2025 14:25:25 GMT</pubDate><content:encoded>&lt;p&gt;这次 Java 网盘项目部署中，AWS EC2 连接不稳定并不是单一问题，而是「代理 DNS 配置」「校园网网络限制」和「TUN 流量转发模式」三者叠加后的结果。&lt;/p&gt;
&lt;p&gt;把现象拆开之后，问题链路会清晰很多。&lt;/p&gt;
&lt;h2&gt;1. 初始报错：DNS 污染导致连接目标错误&lt;/h2&gt;
&lt;p&gt;使用 Clash 代理时，出现该报错的本质是&lt;strong&gt;DNS 解析被篡改&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Clash 默认 DNS 转发规则没有针对 AWS 域名（&lt;code&gt;*.amazonaws.com&lt;/code&gt;）做专门配置，解析请求被代理劫持后返回了虚假 IP，而不是 EC2 的真实公网 IP。&lt;/li&gt;
&lt;li&gt;SSH 客户端基于错误解析结果发起连接，目标主机并不是 AWS EC2 实例，因此被远端主动关闭，触发 &lt;code&gt;Connection closed by remote host&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;这种情况下，即使反复检查 EC2 安全组、入站规则和密钥权限，也无法解决问题，因为连接目标一开始就错了。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以第一层问题不是 SSH，也不是 EC2 配置，而是 DNS。&lt;/p&gt;
&lt;h2&gt;2. 关闭 Clash 后无法 ping 通：校园网境外访问限制&lt;/h2&gt;
&lt;p&gt;关闭 Clash 代理后，出现「无法 ping 通 EC2」的现象，核心是&lt;strong&gt;校园网防火墙的访问控制&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;校园网可能会限制境外 IP 的直接访问，尤其是云服务厂商地址。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ping&lt;/code&gt; 依赖 ICMP，SSH 依赖 TCP 22 端口，这两类流量都有可能被校园网出口策略拦截。&lt;/li&gt;
&lt;li&gt;无代理时，本地流量直接从校园网出口发送，不经过任何转发机制，自然无法绕过这些限制。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以第二层问题是：关闭代理后 DNS 可能正常了，但网络路径不通。&lt;/p&gt;
&lt;h2&gt;3. 关闭 TUN 模式后秒连：规避流量转发异常&lt;/h2&gt;
&lt;p&gt;开启 Clash 的 TUN 模式（虚拟网卡）时连接失败，关闭后秒连，本质是&lt;strong&gt;TUN 模式的流量转发机制与 SSH 协议不兼容&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;TUN 模式会创建虚拟网卡，接管系统所有网络流量。由于 WSL 2 共享 Windows 网络栈，WSL 的流量也会被纳入这条链路。&lt;/li&gt;
&lt;li&gt;流量需要经过「虚拟网卡 → 代理节点」的额外转发，相比应用层代理多了一层干预。&lt;/li&gt;
&lt;li&gt;这个过程中可能出现 MTU 不匹配，导致 SSH 数据包分片异常；也可能出现协议识别或转发规则误判，最终表现为连接重置。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;关闭 TUN 模式后，Clash 只通过应用层规则转发流量。基于已配置好的 AWS 域名或 22 端口规则，流量可以从系统原生网络栈转发到代理节点，既保留了代理绕过校园网限制的能力，又减少了虚拟网卡带来的不确定性，因此实现秒连。&lt;/p&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;整个问题的核心逻辑链是：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Clash DNS 配置不当&lt;/code&gt; → &lt;code&gt;DNS 污染&lt;/code&gt; → &lt;code&gt;SSH 连接错误目标&lt;/code&gt; → &lt;code&gt;关闭 Clash 后校园网阻断境外流量&lt;/code&gt; → &lt;code&gt;关闭 TUN 模式后应用层代理正常转发&lt;/code&gt; → &lt;code&gt;连接恢复&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;本质上，这是代理配置、网络环境和协议转发机制三者的适配问题。解决方向不是盲目重装或反复改安全组，而是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;修正 Clash 的 DNS 规则，避免 AWS 域名被污染；&lt;/li&gt;
&lt;li&gt;保留必要代理，绕过校园网境外访问限制；&lt;/li&gt;
&lt;li&gt;关闭不必要的 TUN 模式，减少 SSH 流量转发异常。&lt;/li&gt;
&lt;/ol&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>连接 AWS EC2 失败：DNS 污染导致解析异常</title><link>https://frank-whw.com/blog/articles/aws-ec2-dns-pollution</link><guid isPermaLink="true">https://frank-whw.com/blog/articles/aws-ec2-dns-pollution</guid><description>从错误 IP、解析超时到代理工具污染，这是一篇完整记录 DNS 失真过程的排障文章。</description><pubDate>Wed, 12 Nov 2025 09:04:59 GMT</pubDate><content:encoded>&lt;h2&gt;问题背景&lt;/h2&gt;
&lt;p&gt;这次问题发生在从 WSL 2 连接 AWS EC2 时。目标实例位于东京区域 &lt;code&gt;ap-northeast-1&lt;/code&gt;，AWS 控制台确认的公网 IP 是 &lt;code&gt;54.95.61.230&lt;/code&gt;，连接方式是 SSH 密钥认证。&lt;/p&gt;
&lt;p&gt;当时的网络环境是校园网，Windows 端运行 FClash 代理工具，WSL 2 共享 Windows 的网络配置。&lt;/p&gt;
&lt;p&gt;| 项目     | 详情                                            |
| -------- | ----------------------------------------------- |
| 客户端   | WSL 2（Ubuntu 子系统），用户名 &lt;code&gt;frank&lt;/code&gt;          |
| 目标服务 | AWS EC2 实例（东京区域 &lt;code&gt;ap-northeast-1&lt;/code&gt;）       |
| 预期配置 | 公网 IP：&lt;code&gt;54.95.61.230&lt;/code&gt;；连接方式：SSH 密钥认证 |
| 网络环境 | 校园网，Windows 端运行 FClash                   |&lt;/p&gt;
&lt;h2&gt;核心现象&lt;/h2&gt;
&lt;h3&gt;SSH 连接到了错误 IP&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;frank@LAPTOP-D1IUBHQH:~$ ssh -i /home/frank/learning/cloud.pem ubuntu@ec2-54-95-61-230.ap-northeast-1.compute.amazonaws.com
kex_exchange_identification: Connection closed by remote host
Connection closed by 28.0.0.22 port 22
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;关键点在于：SSH 最终连接到的是 &lt;code&gt;28.0.0.22&lt;/code&gt;，而不是 AWS 控制台显示的 &lt;code&gt;54.95.61.230&lt;/code&gt;。这说明问题很可能不在 EC2 安全组，而在域名解析阶段。&lt;/p&gt;
&lt;h3&gt;后续出现域名解析失败&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;frank@LAPTOP-D1IUBHQH:~$ ssh -i /home/frank/learning/cloud.pem ubuntu@ec2-54-95-61-230.ap-northeast-1.compute.amazonaws.com
ssh: Could not resolve hostname ec2-54-95-61-230.ap-northeast-1.compute.amazonaws.com: Temporary failure in name resolution
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;后续再次连接时，域名甚至无法解析。也就是说，同一个域名先被解析到错误 IP，随后又出现解析超时，问题进一步指向 DNS 链路。&lt;/p&gt;
&lt;h2&gt;排查过程&lt;/h2&gt;
&lt;h3&gt;验证域名解析结果&lt;/h3&gt;
&lt;p&gt;通过 &lt;code&gt;nslookup&lt;/code&gt; 命令定位解析异常，结果显示 DNS 返回错误 IP：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;frank@LAPTOP-D1IUBHQH:~$ nslookup ec2-54-95-61-230.ap-northeast-1.compute.amazonaws.com
Server:         10.255.255.254    本地私有 DNS 服务器（代理分配）
Address:        10.255.255.254 53

Name:   ec2-54-95-61-230.ap-northeast-1.compute.amazonaws.com
Address: 28.0.0.22    错误解析结果，与 EC2 真实 IP 不符
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;结论很明确：域名解析被污染，返回结果没有指向 AWS EC2 实例的真实公网 IP。&lt;/p&gt;
&lt;h3&gt;排除其他层面问题&lt;/h3&gt;
&lt;p&gt;| 排查方向       | 操作                                 | 结果                                              |
| -------------- | ------------------------------------ | ------------------------------------------------- |
| 校园网直接解析 | Windows 主机执行 &lt;code&gt;nslookup&lt;/code&gt; 相同域名 | 同样解析到 &lt;code&gt;28.0.0.22&lt;/code&gt;，排除 WSL 独立问题         |
| 公共 DNS 测试  | 指定 Google DNS &lt;code&gt;8.8.8.8&lt;/code&gt; 解析       | 仍返回 &lt;code&gt;28.0.0.22&lt;/code&gt;，说明解析请求被拦截或篡改      |
| 代理工具影响   | 关闭 FClash 后重新解析               | 解析恢复为 &lt;code&gt;54.95.61.230&lt;/code&gt;，确认 FClash 是污染源头 |&lt;/p&gt;
&lt;h2&gt;根本原因&lt;/h2&gt;
&lt;p&gt;根本原因是 &lt;strong&gt;FClash 的 DNS 处理导致 AWS 域名解析异常&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;具体机制可以拆成三层：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;FClash 未正确配置 DNS 转发规则，导致 &lt;code&gt;*.amazonaws.com&lt;/code&gt; 的解析请求被劫持，返回虚假 IP &lt;code&gt;28.0.0.22&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;代理侧 DNS 缓存没有及时清理，即使后续调整配置，旧的错误解析结果仍可能被复用。&lt;/li&gt;
&lt;li&gt;WSL 2 共享 Windows 的 DNS 配置，FClash 对 Windows DNS 的修改会影响到 WSL 环境。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;解决方案&lt;/h2&gt;
&lt;h3&gt;临时恢复连接&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;关闭 FClash 代理工具；&lt;/li&gt;
&lt;li&gt;清理系统与 WSL 的 DNS 缓存：&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# WSL 终端执行：清理 WSL 缓存
sudo systemd-resolve --flush-caches

# Windows 管理员终端执行：清理系统缓存
ipconfig /flushdns
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;长期配置 FClash&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;打开 FClash → 「设置」→「DNS 设置」；&lt;/li&gt;
&lt;li&gt;启用「自定义 DNS 服务器」，添加加密 DNS（防止劫持）：
&lt;ul&gt;
&lt;li&gt;Cloudflare DNS：&lt;code&gt;1.1.1.1&lt;/code&gt;（DoH 地址：&lt;code&gt;https://cloudflare-dns.com/dns-query&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;Google DNS：&lt;code&gt;8.8.8.8&lt;/code&gt;（DoH 地址：&lt;code&gt;https://dns.google/dns-query&lt;/code&gt;）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;关闭「虚假 DNS」「DNS 劫持」功能，开启「DNS 缓存自动清理」。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;添加 AWS 域名专属规则，确保解析走代理且不被污染：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;「规则」→「添加规则」，选择「域名后缀匹配」；&lt;/li&gt;
&lt;li&gt;匹配值：&lt;code&gt;amazonaws.com&lt;/code&gt;（覆盖所有 AWS 服务域名）；&lt;/li&gt;
&lt;li&gt;动作：「代理」（若校园网封锁 AWS，需选择有效代理节点）；&lt;/li&gt;
&lt;li&gt;调整规则优先级至顶部（优先匹配）。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;验证修复效果&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 解析验证：正确返回 EC2 真实 IP
frank@LAPTOP-D1IUBHQH:~$ nslookup ec2-54-95-61-230.ap-northeast-1.compute.amazonaws.com
Server:         1.1.1.1
Address:        1.1.1.1 53

Name:   ec2-54-95-61-230.ap-northeast-1.compute.amazonaws.com
Address: 54.95.61.230

# SSH 连接验证：成功建立会话
frank@LAPTOP-D1IUBHQH:~$ ssh -i /home/frank/learning/cloud.pem ubuntu@ec2-54-95-61-230.ap-northeast-1.compute.amazonaws.com
Welcome to Ubuntu 22.04.3 LTS (GNU/Linux 5.15.0-1019-aws x86_64)
...
ubuntu@ip-xxx-xxx-xxx-xxx:~$
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;这次排障的关键不是 SSH 本身，而是先确认“连接目标到底是谁”。当 SSH 报错里出现了非预期 IP &lt;code&gt;28.0.0.22&lt;/code&gt; 时，就应该优先怀疑 DNS 链路。&lt;/p&gt;
&lt;p&gt;最终问题链路是：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;FClash DNS 配置异常&lt;/code&gt; → &lt;code&gt;AWS 域名被污染&lt;/code&gt; → &lt;code&gt;SSH 连接到错误 IP&lt;/code&gt; → &lt;code&gt;连接被远端关闭或解析失败&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;解决思路也很直接：修正代理 DNS 配置，清理缓存，并为 AWS 域名设置明确的分流规则。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>WSL2 的 NAT 和 Mirrored 模式到底有什么区别</title><link>https://frank-whw.com/blog/articles/wsl2-network-modes</link><guid isPermaLink="true">https://frank-whw.com/blog/articles/wsl2-network-modes</guid><description>从一个真实端口冲突问题出发，我把 WSL2 的 NAT 和 Mirrored 两种网络模式重新梳理了一遍。</description><pubDate>Mon, 10 Nov 2025 02:57:43 GMT</pubDate><content:encoded>&lt;h2&gt;问题起因&lt;/h2&gt;
&lt;p&gt;之前每次打开 WSL2，顶部都会出现这个提示：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;wsl: 检测到 localhost 代理配置，但未镜像到 WSL。NAT 模式下的 WSL 不支持 localhost 代理。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;搜索之后，我参考了&lt;a href=&quot;https://zhuanlan.zhihu.com/p/15762609815&quot;&gt;知乎帖子&lt;/a&gt;里的方法，大概率是切换到了 Mirrored 网络模式，或配置了代理镜像。这个代理报错确实立刻解决了。&lt;/p&gt;
&lt;p&gt;但新的问题很快出现：在 WSL2 中运行 Java 后端程序时，JMX 端口冲突了。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;Error: JMX connector server communication error: service:jmx:rmi://0.0.0.0:26203
jdk.internal.agent.AgentConfigurationError: java.rmi.server.ExportException: Port already in use: 26203; nested exception is:
    java.net.BindException: Address already in use
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就引出了一个问题：WSL2 的 NAT 和 Mirrored 模式到底有什么区别？&lt;/p&gt;
&lt;h2&gt;先说结论&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;NAT 模式&lt;/strong&gt;：WSL2 拥有独立的私有网络和端口空间，与 Windows 宿主机的端口互不干扰。即使 Windows 占用了 &lt;code&gt;26203&lt;/code&gt;，WSL2 里的 Java 程序仍然可能正常绑定这个端口。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mirrored 模式&lt;/strong&gt;：WSL2 与 Windows 宿主机共享网络接口和端口空间，更接近“同一台设备上的不同进程”。如果 Windows 已经有进程占用 &lt;code&gt;26203&lt;/code&gt;，WSL2 再绑定同一端口就会触发 &lt;code&gt;Address already in use&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;| 对比维度           | NAT 模式                        | Mirrored 模式              |
| ------------------ | ------------------------------- | -------------------------- |
| &lt;strong&gt;默认状态&lt;/strong&gt;       | 默认启用                        | 需手动启用（Win11 22H2+）  |
| &lt;strong&gt;IP 分配&lt;/strong&gt;        | 私有子网 IP（动态）             | 复用宿主机 IP              |
| &lt;strong&gt;局域网可达性&lt;/strong&gt;   | 外部设备无法直接访问            | 外部设备可直接访问         |
| &lt;strong&gt;端口转发&lt;/strong&gt;       | 需手动配置                      | 无需配置（共享宿主机端口） |
| &lt;strong&gt;网络切换适应性&lt;/strong&gt; | 较差（切换网络后需重新获取 IP） | 优秀（同步宿主机网络）     |
| &lt;strong&gt;性能&lt;/strong&gt;           | 中等                            | 中等                       |
| &lt;strong&gt;兼容性&lt;/strong&gt;         | 最佳（全平台支持）              | 有限（仅 Win11 22H2+）     |&lt;/p&gt;
&lt;h2&gt;NAT 模式：默认的网络地址转换&lt;/h2&gt;
&lt;h3&gt;工作原理&lt;/h3&gt;
&lt;p&gt;NAT 是 WSL2 的默认网络模式，基于 Hyper-V 虚拟交换机实现。&lt;/p&gt;
&lt;p&gt;Windows 会创建一个内部虚拟网络，通常是 &lt;code&gt;WSL&lt;/code&gt; 虚拟交换机。WSL2 实例会被分配一个私有子网 IP，例如 &lt;code&gt;172.x.x.x&lt;/code&gt; 网段，再通过宿主机网络接口做 NAT 转换，从而访问外部网络。&lt;/p&gt;
&lt;h3&gt;核心特性&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;网络可达性&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;WSL2 可以访问宿主机和外部网络；&lt;/li&gt;
&lt;li&gt;宿主机可以通过 WSL2 的私有 IP 访问 WSL2；&lt;/li&gt;
&lt;li&gt;局域网内其他设备通常无法直接访问 WSL2，需要额外配置端口转发或桥接。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IP 动态性&lt;/strong&gt;：WSL2 重启后可能分配新的私有 IP，稳定性较差。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;端口转发&lt;/strong&gt;：外部设备访问 WSL2 服务时，需要手动在 Windows 防火墙和虚拟交换机中配置端口转发规则，或借助自动转发工具。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;性能&lt;/strong&gt;：基础网络性能满足日常开发需求，但 NAT 转换会带来轻微开销。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;适用场景&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;本地开发（如运行数据库、后端服务，仅需宿主机访问）。&lt;/li&gt;
&lt;li&gt;无需局域网内其他设备交互的场景。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Mirrored 模式：与宿主机共享网络&lt;/h2&gt;
&lt;h3&gt;工作原理&lt;/h3&gt;
&lt;p&gt;Mirrored 是 Windows 11 22H2 及以上版本新增的模式，核心是&lt;strong&gt;将 WSL2 的网络接口与宿主机网络接口镜像对齐&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;开启后，WSL2 会共享宿主机的网络配置，包括 Wi-Fi、以太网、VPN 等。它更像是和宿主机处于同一网络层面，因此拥有与宿主机相同的网络可达性。&lt;/p&gt;
&lt;h3&gt;核心特性&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;网络可达性&lt;/strong&gt;：WSL2 与宿主机共享网络环境，可以直接访问局域网内其他设备；外部设备也能通过宿主机 IP 直接访问 WSL2 服务，无需额外端口转发。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;动态网络切换&lt;/strong&gt;：宿主机从 Wi-Fi 切换到以太网时，WSL2 网络会同步更新。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IP 分配&lt;/strong&gt;：WSL2 不再单独分配私有 IP，而是复用宿主机的网络身份。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;兼容性&lt;/strong&gt;：对 VPN、企业网络策略的兼容性更好。部分复杂 VPN 环境下，NAT 模式可能失效，而 Mirrored 模式可以正常工作。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;限制&lt;/strong&gt;：仅支持 Windows 11 22H2 及以上版本。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;适用场景&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;需要局域网内其他设备访问 WSL2 服务，例如测试环境共享、多设备联调。&lt;/li&gt;
&lt;li&gt;宿主机频繁切换网络（如笔记本电脑移动办公）。&lt;/li&gt;
&lt;li&gt;需通过 VPN 访问企业内网的场景。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;这次报错的原因&lt;/h2&gt;
&lt;p&gt;切换到 Mirrored 模式后，WSL2 与 Windows 共享端口空间。Java 程序试图绑定的 &lt;code&gt;26203&lt;/code&gt; 端口，已经被 Windows 宿主机中的其他进程占用，例如另一个 Java 程序或后台服务，于是触发端口冲突。&lt;/p&gt;
&lt;p&gt;这也是为什么 NAT 模式下程序可以正常运行，而 Mirrored 模式下会报错。&lt;/p&gt;
&lt;h2&gt;解决方法&lt;/h2&gt;
&lt;h3&gt;1. 定位占用端口的进程&lt;/h3&gt;
&lt;p&gt;在 Windows 中执行：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;netstat -ano | findstr :26203
tasklist | findstr &amp;#x3C;PID&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 WSL2 中执行：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo netstat -tulpn | grep 26203
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. 释放冲突端口&lt;/h3&gt;
&lt;p&gt;如果占用进程不是必要程序，可以直接在 Windows 任务管理器中按 PID 找到并结束它，或在 WSL2 中执行：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;kill -9 &amp;#x3C;PID&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. 修改 Java 程序端口&lt;/h3&gt;
&lt;p&gt;如果无法释放端口，就把 Java 程序的 JMX 端口改成未被占用的值，例如 &lt;code&gt;26204&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;java -Dcom.sun.management.jmxremote \
     -Dcom.sun.management.jmxremote.port=26204 \
     -Dcom.sun.management.jmxremote.rmi.port=26204 \
     -Dcom.sun.management.jmxremote.ssl=false \
     -Dcom.sun.management.jmxremote.authenticate=false \
     -jar your-program.jar
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;NAT 和 Mirrored 没有绝对好坏，区别在于网络隔离程度。&lt;/p&gt;
&lt;p&gt;NAT 更稳、更隔离，适合大多数本地开发；Mirrored 更接近宿主机网络，适合局域网访问、VPN 和代理场景，但也更容易遇到宿主机端口冲突。&lt;/p&gt;
&lt;p&gt;这次问题的本质就是：为了解决代理镜像问题切到了 Mirrored 模式，同时引入了端口空间共享，最终暴露出 Windows 端已有进程占用 &lt;code&gt;26203&lt;/code&gt; 的冲突。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>RoomieSync：从课程作业到创业冲动</title><link>https://frank-whw.com/blog/projects/roomiesync</link><guid isPermaLink="true">https://frank-whw.com/blog/projects/roomiesync</guid><description>RoomieSync 对我来说不只是一个项目原型，它也逼着我第一次认真面对独立开发和创业这件事。</description><pubDate>Fri, 07 Nov 2025 06:09:19 GMT</pubDate><content:encoded>&lt;h2&gt;起点&lt;/h2&gt;
&lt;p&gt;我很早之前就有了做 RoomieSync 的想法。最初的动机很简单：希望给学弟学妹们一个自主选择室友的机会。&lt;/p&gt;
&lt;p&gt;借着 Web 编程课程的机会，我做出了第一版。当时受课程要求限制，必须使用 HTML、CSS、JavaScript 三件套，只能采用比较基础的前后端分离架构。UI 虽然还算美观，但整体远没有达到我满意的程度。无论是业务逻辑，还是底层架构，都有不少可以重做的地方。&lt;/p&gt;
&lt;h2&gt;重新开始&lt;/h2&gt;
&lt;p&gt;后来暑假参加了两场黑客松，见识了很多技术很强的人，也第一次深入接触到 vibe coding 这种越来越主流的开发模式。&lt;/p&gt;
&lt;p&gt;从他们身上我学到了很多实用技巧，也逐渐决定抛开原来的束缚，真正开始独立开发。借助 AI 的支持，我在大一就体验了项目经理、产品经理、开发工程师、架构师等一系列角色。&lt;/p&gt;
&lt;p&gt;比较遗憾的是，我没有全程记录这段开发过程。现在回想起来，那应该会是一段很有意思的材料。&lt;/p&gt;
&lt;h2&gt;独立开发的现实&lt;/h2&gt;
&lt;p&gt;开发进行到一半时，我逐渐意识到，独立开发，或者说创业，绝不是一件容易的事。它需要非常强的信念和内驱力，也需要长期承受不确定性。&lt;/p&gt;
&lt;p&gt;于是我开始寻找共同开发的伙伴。但那时 RoomieSync 已经完成了约 80%，对很多人来说，接手一个已有项目本身就有难度，需要大量引导。这也让我后来能理解，为什么李叔没有让我直接参与他的项目：已有项目不是不能接，而是接入成本确实很高。&lt;/p&gt;
&lt;p&gt;另一方面，很多人其实不是没有能力，而是对自己的能力还不够自信。&lt;/p&gt;
&lt;h2&gt;AI 带来的变化&lt;/h2&gt;
&lt;p&gt;事实上，AI 已经大幅降低了编程门槛。很多事情只有真正动手尝试，才会发现并没有想象中那么难。&lt;/p&gt;
&lt;p&gt;但这也给我敲响了警钟：如果 AI 编程继续这样发展，在不远的将来，纯粹程序员的路径可能会越来越窄。会写代码当然重要，但只会写代码可能不再够用。理解产品、判断方向、组织资源、持续交付，可能会变得更加关键。&lt;/p&gt;
&lt;h2&gt;关于创业的想法&lt;/h2&gt;
&lt;p&gt;就我个人而言，我一直更倾向于本科就业，而不是读研。在这个暑假之前，我从未认真考虑过创业。但现在我越来越相信，创业也许是我当下最应该认真思考的破局之路。&lt;/p&gt;
&lt;p&gt;一些初步的思考：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;必须找到同样具备内驱力、真正认同创业方向，并愿意全情投入的伙伴；&lt;/li&gt;
&lt;li&gt;创业过程中一定会遇到无数未曾预料的问题，唯有保持信息敏感、不断学习，才能关关难过关关过；&lt;/li&gt;
&lt;li&gt;绝不能被他人的眼光束缚自己。且视他人之疑目如盏盏鬼火，大胆地去走你的夜路；&lt;/li&gt;
&lt;li&gt;如果用户使用积极性不高，就想办法将他们的幸福感与平台深度绑定，让产品真正融入他们的需求与情感。&lt;/li&gt;
&lt;/ol&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>OpenChain：第一次把工程思维完整用在项目里</title><link>https://frank-whw.com/blog/projects/openchain</link><guid isPermaLink="true">https://frank-whw.com/blog/projects/openchain</guid><description>这篇记录的不只是一个比赛项目，更是我第一次真正用工程化方式推进完整作品的过程。</description><pubDate>Mon, 31 Mar 2025 12:35:14 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;这是我第一次把&lt;a href=&quot;/blog/thoughts/lifelong-learning-system&quot;&gt;关于终身学习体系的思考&lt;/a&gt;里提到的工程思维，完整用在大学阶段的项目实践中。为了记录这个过程，写下这篇复盘：&lt;a href=&quot;https://github.com/Frank-whw/OpenChain&quot;&gt;OpenChain&lt;/a&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;What&lt;/h2&gt;
&lt;p&gt;OpenChain 有双重属性：它既是我大一学年修读的一门大二专业基础课的期末大作业，也是参与 &lt;a href=&quot;https://competition.atomgit.com/competitionInfo?id=557cfb17b901c9420329327259f13c39&quot;&gt;OpenRank&lt;/a&gt; 比赛的正式作品。比较幸运的是，我们最终拿到了全国三等奖。&lt;/p&gt;
&lt;p&gt;简单来说，OpenChain 聚焦的是开源生态中的可持续发展问题。它希望通过构建“人 - 项目”的双向匹配机制，帮助开发者找到更适合自己的开源项目，也帮助项目找到更合适的贡献者。&lt;/p&gt;
&lt;h2&gt;Analysis&lt;/h2&gt;
&lt;p&gt;客观来说，项目立意还不够深。在真正见过大项目、大场面的评委面前，它确实略显单薄，实际应用价值也还有待验证。&lt;/p&gt;
&lt;p&gt;核心难点在于&lt;strong&gt;推荐算法&lt;/strong&gt;的有效性验证与优化。个人认为，真正关键的推荐数据源应该包括浏览历史、页面停留时间、交互行为等更细粒度的数据。但 OpenChain 当前主要依赖有限的标签数据进行推荐，它能否精准理解并满足用户需求，还需要更多理论和实践验证。&lt;/p&gt;
&lt;p&gt;主观来说，OpenChain 的完成对我意义很大。前端主要借助 v0.dev，后端以及前后端连接主要借助 Cursor。虽然代码主体很大程度上由 AI 工具辅助完成，但作为使用者，我仍然学到了很多：包括对前后端整体框架的理解、对项目推进节奏的把控，以及面对复杂问题时心态的稳定。&lt;/p&gt;
&lt;p&gt;我越来越相信，用自然语言实现全栈开发是一个可以看见的未来。至少对有一定编程基础的初级开发者来说，全栈开发的门槛已经不像五年前，甚至一年前那么高。面对 AI 技术的快速发展，传统意义上对冗杂代码细节的深度钻研，是否仍然是开发者的唯一核心能力，值得重新思考。&lt;/p&gt;
&lt;p&gt;所以我可以很坦然地说：这个项目是 &lt;strong&gt;coded by AI, but designed by Frank&lt;/strong&gt;。&lt;/p&gt;
&lt;h2&gt;Process&lt;/h2&gt;
&lt;p&gt;作为团队负责人，我主要负责项目全生命周期的管理与推进。&lt;/p&gt;
&lt;h3&gt;初期：确定方向&lt;/h3&gt;
&lt;p&gt;项目立意我放了很长一段时间。原因也很简单：我只愿意在自己真正感兴趣的事情上投入时间。&lt;/p&gt;
&lt;p&gt;前期，推荐算法的实现迭代了好几版。从遍历共同作者，到优化相似度算法，再到最终的推荐池算法，中间有很多思维碰撞。这个过程其实很好玩。&lt;/p&gt;
&lt;h3&gt;后期：在前端展示和推荐算法之间取舍&lt;/h3&gt;
&lt;p&gt;当前后端基本完成后，我们有两个方向可以继续投入：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;完善前端，让最终展示效果更好看；&lt;/li&gt;
&lt;li&gt;完善后端，尤其是推荐算法。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;我始终认为，以推荐算法为核心的推荐流程才是这个项目真正有意义的部分。所以后期大量时间都花在调试和验证上：不断调整相似度指标各个维度的权重，让结果尽可能“看起来有意义”。&lt;/p&gt;
&lt;p&gt;这个阶段很枯燥，但也最接近工程实践本身。&lt;/p&gt;
&lt;h3&gt;末期：文档和展示可能才是关键&lt;/h3&gt;
&lt;p&gt;现在回头看，我怀疑这个阶段才是我们获奖的关键。&lt;/p&gt;
&lt;p&gt;复赛进入 Top 16 只由两位评委决定，运气占了很大一部分。同时，评委不一定有足够时间完整运行和理解项目，所以他们对项目价值的判断，很大程度来自说明文件和展示材料。&lt;/p&gt;
&lt;p&gt;因此我写了一份“过于详细”的 README，队友也做了一份“过于详细”的演示视频。事实证明，这些材料确实提高了项目被理解的概率。&lt;/p&gt;
&lt;h3&gt;路演：宝贵但不完美的经历&lt;/h3&gt;
&lt;p&gt;由于时间冲突，很多学长学姐只能通过线上答疑和线下找人展示的方式完成最终路演。出于对更高奖金的追求，也经过权衡，我决定飞到武汉参加。&lt;/p&gt;
&lt;p&gt;从体验上说，这段经历很宝贵；从效果上说，并不理想。&lt;/p&gt;
&lt;p&gt;一方面，项目 PPT 还不够优秀；另一方面，项目本身也确实还不够强。我个人的展示能力也有限，对麦克风不熟悉，导致现场音量不够稳定。为了赶时间，我把 26 分钟的展示视频压缩到 3 分钟，代价是场馆音响几乎听不清。&lt;/p&gt;
&lt;p&gt;不过最后 5 分钟的提问环节，我觉得自己还是比较有条理地正面回答了评委老师的问题。现在回想起来，当时好像也没有特别紧张。&lt;/p&gt;
&lt;h2&gt;Values&lt;/h2&gt;
&lt;p&gt;这次项目最大的收获，是第一次真正体会到工程思维的魅力。&lt;/p&gt;
&lt;p&gt;复杂项目并不是靠一口气冲完的，而是要拆解成一个个可操作的阶段：从项目立意、算法优化、方向取舍，到最终成果展示，每个阶段都有自己的重点和节奏。&lt;/p&gt;
&lt;h2&gt;Future&lt;/h2&gt;
&lt;p&gt;后面要尽可能独立完成更高难度的项目。&lt;/p&gt;
&lt;p&gt;简单的前后端项目当然有练手价值，但不能一直停留在这个层面。下一步更应该做的是：找到真正有挑战、有壁垒、也更值得长期投入的问题。&lt;/p&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>关于终身学习体系的思考</title><link>https://frank-whw.com/blog/thoughts/lifelong-learning-system</link><guid isPermaLink="true">https://frank-whw.com/blog/thoughts/lifelong-learning-system</guid><description>从学生思维、工程思维到个人学习系统，这篇文章记录了我开始认真规划长期成长的过程。</description><pubDate>Mon, 31 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;这几天看了一些前辈的文章，很有触动。结合自己的经历，也试着整理一下我对长期成长和学习系统的想法。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;关于我&lt;/h2&gt;
&lt;p&gt;我给自己 2025 年定下的目标是：“别急，慢慢来。”&lt;/p&gt;
&lt;p&gt;但作为大学四年里的第一年，我也必须承认：自己需要打破过去 12 年学生思维的惯性，同时认真思考未来的方向。和顶尖院校的同学不同，身处普通 985 的我，在考研、保研和就业之间需要做更多权衡。&lt;/p&gt;
&lt;p&gt;和许多优秀的学长学姐、老师交流之后，我逐渐意识到，一些原本设想中的目标并没有想象中现实。比如保研去交大这类路径，对我来说并不一定是最稳妥、最合理的选择。这个问题曾经让我陷入过一段迷茫和停滞。&lt;/p&gt;
&lt;p&gt;但现在回头看，焦虑本身并不会带来答案。与其焦虑，不如脚踏实地。&lt;/p&gt;
&lt;p&gt;慢慢来吧，从舍弃学生思维开始，从主动构建自己的终身学习体系开始。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;舍弃学生思维&lt;/h2&gt;
&lt;h3&gt;学生思维的局限&lt;/h3&gt;
&lt;p&gt;在我看来，学生思维主要有两个问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;视角过于理想化&lt;/strong&gt;：学生常常把世界想象得过于理想，认为一切都可以按照逻辑和规则推导出来。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;目标容易错位&lt;/strong&gt;：大学并不是研究如何赚钱的地方。如果只顾着“卷”学业，却忽视实践的意义，反而容易让自己的边际收益递减，也让自己承受更多不必要的痛苦。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;如何转变&lt;/h3&gt;
&lt;p&gt;要摆脱学生思维，我觉得至少需要做到四点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;多输出&lt;/strong&gt;：通过写博客来整理和表达自己的思考。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;多交流&lt;/strong&gt;：虽然在国内教育环境中，同级之间的竞争关系有时比较紧张，但我们依然可以主动建立真诚的连接。
&lt;ul&gt;
&lt;li&gt;真诚对待那些真诚对待你的人。&lt;/li&gt;
&lt;li&gt;多和学长学姐交流，打破年级之间的信息隔阂。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;多反思&lt;/strong&gt;：反思不应只是空想，而是要通过文字等具体形式沉淀下来。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;改变思维模式&lt;/strong&gt;：认识到&lt;strong&gt;理想/逻辑的世界与现实/物理的世界并不相同&lt;/strong&gt;。接受这一点之后，我们才能更灵活地应对复杂现实。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2&gt;工程思维与流式规划&lt;/h2&gt;
&lt;h3&gt;什么是工程思维和流式规划？&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;工程思维&lt;/strong&gt;：将任务视为一个分阶段、分步骤的项目，通过拆解步骤来推进。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;流式规划&lt;/strong&gt;：将生活中的不同任务划分为多个类别（称为“流”），并在这些流之间快速切换。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;为什么需要它们？&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;工程思维&lt;/strong&gt;的优势在于能让人快速上手并投入实践。现实世界不同于考试，你永远无法提前准备好所有内容，只能根据情况动态调整。机会稍纵即逝，过度准备反而可能让人错过窗口。当然，这不意味着可以忽略基础知识：扎实的基础仍然是完成任务的前提。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;流式规划&lt;/strong&gt;的目的，是避免&lt;strong&gt;边际效应递减&lt;/strong&gt;。长时间专注于同一任务，效率会逐渐下降；但时间投入太少，又难以形成实际产出。因此，我们需要把每天的时间划分为多个“流”，并像管理进程一样及时切换。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实现这两点，需要培养&lt;strong&gt;自我感知&lt;/strong&gt;，也就是定期问自己：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;我现在在做什么？&lt;/li&gt;
&lt;li&gt;目前处于某个项目的哪个阶段？&lt;/li&gt;
&lt;li&gt;当前任务属于哪个流？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果没有这些反思，就很容易陷入低效状态。&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;构建个人终身学习体系&lt;/h2&gt;
&lt;h3&gt;为什么需要？&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;信息爆炸&lt;/strong&gt;：当今世界知识更新迭代的速度越来越快。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;记忆遗忘&lt;/strong&gt;：人类的记忆力有限。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;效率需求&lt;/strong&gt;：现代社会对学习效率的要求逐步提升。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;如何实现？&lt;/h3&gt;
&lt;h4&gt;远离低质量信息&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Frank-whw/img/main/blog/202501051447320.png&quot; alt=&quot;image.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;现代社会并不缺乏优质信息，真正稀缺的是筛选优质信息的能力。我的一些通用原则是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;越大众的渠道，噪音往往越大；越小众的圈子，内容质量反而可能更高。&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;忽略缺乏基本科学素养的人提供的信息。很多时候，一个人是否可信，可以先通过常识问题做初步判断。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;为知识付费是合理的行为&lt;/strong&gt;，高质量信息往往不是免费的。&lt;/li&gt;
&lt;li&gt;谨慎追热点，热点信息往往充斥着低质量内容。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;区分事实与观点&lt;/strong&gt;：事实接受即可，观点则需要独立思考。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;写作的意义&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;深度学习&lt;/strong&gt;：阅读时，我们被动接受作者的观点；而写作要求我们查阅资料、分析问题，甚至总结多年经验，从而促进深度思考。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;高质量社交&lt;/strong&gt;：一篇好的文章能够建立信任并形成深度连接，而灌水式聊天很难做到这一点。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;创造机会&lt;/strong&gt;：有些文章可能帮助我进入新的领域，有些可能吸引更有经验的人合作，有些也可能让我结识更多志同道合的朋友。写作的价值无法单纯用阅读量衡量。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Reference&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://www.bmpi.dev/self/build-personal-knowledge-system/&quot;&gt;构建终身学习体系进行自我提升 · BMPI&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item><item><title>Docker 从入门到实践：以 DataLab 环境配置为例</title><link>https://frank-whw.com/blog/articles/docker-datalab-practice</link><guid isPermaLink="true">https://frank-whw.com/blog/articles/docker-datalab-practice</guid><description>这篇文章试图用足够平实的方式，把 Docker 的基本概念和 DataLab 环境配置真正讲清楚。</description><pubDate>Fri, 07 Feb 2025 04:14:15 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;“明明在我的电脑上是可以运行的。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在部署 &lt;a href=&quot;/blog/projects/openchain&quot;&gt;OpenChain&lt;/a&gt; 时，我曾深陷环境配置的泥潭。虚拟机当然可以解决环境隔离问题，但它也带来了资源占用高、操作冗余、启动缓慢等问题。相比之下，Docker 更轻，也更适合开发环境复现。&lt;/p&gt;
&lt;p&gt;另外，在摸索用 Docker 配置 Ubuntu 环境运行 DataLab 时，我发现网上教程并不多。已有内容也经常充满术语和跳步，对新手不太友好。所以这篇文章会尽量用平实的方式，把 Docker 基本概念和 DataLab 环境配置讲清楚。&lt;/p&gt;
&lt;h2&gt;1. Docker 介绍&lt;/h2&gt;
&lt;h3&gt;1.1 容器化是什么&lt;/h3&gt;
&lt;p&gt;Docker 是一个开源容器化平台。它通过操作系统级虚拟化技术，把应用程序及其依赖环境（代码、运行时、系统工具、系统库等）打包成标准化、轻量级的&lt;strong&gt;容器&lt;/strong&gt;（Container）。&lt;/p&gt;
&lt;p&gt;相较于传统虚拟机：&lt;/p&gt;
&lt;p&gt;| 特性       | Docker容器 | 虚拟机   |
| ---------- | ---------- | -------- |
| 虚拟化层级 | OS级       | 硬件级   |
| 启动速度   | 秒级       | 分钟级   |
| 资源占用   | MB级       | GB级     |
| 性能损耗   | &amp;#x3C;5%        | 15-20%   |
| 镜像大小   | 通常&amp;#x3C;100MB | 通常&gt;1GB |&lt;/p&gt;
&lt;p&gt;（数据来源：Docker官方基准测试报告）&lt;/p&gt;
&lt;h3&gt;1.2 核心概念解析&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;镜像（Image）&lt;/strong&gt;：不可变的模板文件，包含构建容器所需的完整指令。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;容器（Container）&lt;/strong&gt;：镜像的可运行实例，拥有独立文件系统和资源隔离。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;仓库（Registry）&lt;/strong&gt;：用于存储和分发镜像的服务，例如 Docker Hub。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Volume&lt;/strong&gt;：持久化数据存储方案，用来突破容器生命周期限制。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;2. Docker安装&lt;/h2&gt;
&lt;h3&gt;2.1 Windows 11 专业版安装指南&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;访问 &lt;a href=&quot;https://www.docker.com/products/docker-desktop/&quot;&gt;Docker Desktop for Windows&lt;/a&gt; 下载安装包。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;启用系统级支持：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;控制面板 → 程序 → 启用或关闭 Windows 功能；&lt;/li&gt;
&lt;li&gt;勾选「Hyper-V」和「Windows Subsystem for Linux」。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;安装时选择 WSL2 后端：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-powershell&quot;&gt;# 验证 WSL 版本
wsl --list --verbose

# 设置默认版本
wsl --set-default-version 2
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;架构选择建议&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;WSL2：推荐开发使用，提供完整 Linux 内核，I/O 性能更好。&lt;/li&gt;
&lt;li&gt;Hyper-V：适合企业级应用，支持动态内存分配、故障转移集群等高级虚拟化功能。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;2.2 镜像加速配置&lt;/h3&gt;
&lt;p&gt;针对国内网络环境，可以配置 USTC 镜像源，提升镜像下载稳定性和速度。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Frank-whw/img/main/blog/202502071010971.png&quot; alt=&quot;image.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;打开 Docker Desktop → Settings → Docker Engine，替换 &lt;code&gt;daemon.json&lt;/code&gt; 配置：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;registry-mirrors&quot;: [&quot;https://docker.mirrors.ustc.edu.cn&quot;],
  &quot;features&quot;: {
    &quot;buildkit&quot;: true // 启用新一代构建工具
  },
  &quot;experimental&quot;: false // 生产环境禁用实验特性
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;应用配置并重启服务：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;systemctl restart docker  # Linux
Get-Service docker | Restart-Service  # PowerShell
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3. 配置 Docker 镜像与容器&lt;/h2&gt;
&lt;h3&gt;3.1 拉取 Ubuntu 镜像&lt;/h3&gt;
&lt;p&gt;可以直接在 Docker Desktop 图形界面中搜索 Ubuntu，然后拉取最新版本：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Frank-whw/img/main/blog/202502071028767.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;也可以使用命令行：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker pull ubuntu:latest
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3.2 创建容器&lt;/h3&gt;
&lt;p&gt;图形化创建时，重点关注几个配置：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/Frank-whw/img/main/blog/202502071042275.png&quot; alt=&quot;image.png&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Container name&lt;/strong&gt;：容器名称，自定义即可。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Port&lt;/strong&gt;：端口映射，根据实际服务需要配置。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Volume&lt;/strong&gt;：卷挂载，用于设置主机和容器之间的共享目录。这样可以在主机上编辑代码，在容器内编译和运行。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Environment variables&lt;/strong&gt;：环境变量，DataLab 场景下暂时可以不配置。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;命令行创建示例：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker run -it -v &amp;#x3C;Host path&gt;:&amp;#x3C;Container path&gt; --name &amp;#x3C;Container name&gt; ubuntu:latest
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;4. 配置 DataLab 环境&lt;/h2&gt;
&lt;p&gt;进入容器后，按下面步骤配置 DataLab：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;更新软件包列表：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;apt-get update
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;安装 &lt;code&gt;wget&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;apt-get install -y wget
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;切换到共享文件夹：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cd CSapp
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;从官网下载 DataLab 源码包：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;wget http://csapp.cs.cmu.edu/3e/datalab-handout.tar
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;解压源码包：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;tar xvf datalab-handout.tar
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;进入 &lt;code&gt;datalab-handout&lt;/code&gt; 文件夹。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;安装编译所需工具：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;apt install -y build-essential
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;build-essential&lt;/code&gt; 包含 GCC、G++、&lt;code&gt;make&lt;/code&gt; 以及其他编译所需的基础库和头文件。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;5. Finish&lt;/h2&gt;
&lt;p&gt;接下来就可以在本机编辑器中编写 &lt;code&gt;bit.c&lt;/code&gt;，再到 Docker 里的 Ubuntu 环境中编译和运行代码。&lt;/p&gt;
&lt;p&gt;容器化不是银弹，但它确实是现代软件工程的基本技能。当再次面对 “Works on my machine” 的困境时，我们至少可以更有底气地说：It works on Docker.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.docker.com/&quot;&gt;Docker官方文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://csapp.cs.cmu.edu/&quot;&gt;CSAPP官网&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mirrors.ustc.edu.cn/&quot;&gt;中国科学技术大学镜像站&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded><h:img src="undefined"/><enclosure url="undefined"/></item></channel></rss>