<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="/rss.xsl"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title><![CDATA[我的博客]]></title>
    <link>https://daichangyu.com/zh</link>
    <description><![CDATA[个人技术博客]]></description>
    <language>zh</language>
    <atom:link href="https://daichangyu.com/api/rss?locale=zh" rel="self" type="application/rss+xml" />
    
    <item>
      <title><![CDATA[Mac/Apple TV 影音全指南：Infuse、VidHub、SenPlayer、Emby 到底该选谁？]]></title>
      <link>https://daichangyu.com/zh/blog/mac-apple-tv-ying-yin-quan-zhi-nan-infuse-vidhub-senplayer-e-zhihu-2034002534860370939</link>
      <guid isPermaLink="true">https://daichangyu.com/zh/blog/mac-apple-tv-ying-yin-quan-zhi-nan-infuse-vidhub-senplayer-e-zhihu-2034002534860370939</guid>
      <description><![CDATA[《Mac/Apple TV 影音全指南：Infuse、VidHub、SenPlayer、Emby 到底该选谁？》

如果你刚刚购入 Mac 或 Apple TV，想要打造一套精美的“家庭影院”海报墙，却在 App Store 琳琅满目的播放器中迷失了方向，这篇文章就是为你写的。

今天我们把目前市面上热度最高的四款 App——**Infuse、VidHub、SenPlayer、Emby** 放在一起，拆开了、揉碎了告诉你哪款才是你的“本命”。

* * *

### 一、 影音界的“高岭之花”：Infuse

**关键词：** 颜值巅峰、画质天花板、贵。

Infuse 几乎是所有 Apple 用户的终极目标。它的 UI 设计完全遵循 Apple 的原生美学，极其优雅。

-   **核心优势：**

-   **音画双绝：** 它对杜比视界（Dolby Vision）、全景声（Atmos）的支持是业内最稳的，色彩映射极其精准，如果你是原盘党（蓝光 4K），它能压榨出你显示器的每一分性能。
-   **全家桶同步：** 通过 iCloud 同步，你在 Mac 上看了一半，出门在 iPhone 上点开就能接着看。

  

-   **痛点：**

-   **价格贵：** 订阅制和昂贵的终身买断让很多新手望而却步。
-   **网盘刮削慢：** 面对超大容量的云盘，它的扫库速度像是在“绣花”。

  

-   **适合谁：** 预算充足、追求极致画质、强迫症般的视觉洁癖患者。

* * *

### 二、 网盘党的“性价比战神”：VidHub

**关键词：** 阿里云盘/115 亲儿子、扫库飞快、高性价比。

作为后起之秀，VidHub 精准地切中了国内用户的痛点：**网盘。**

-   **核心优势：**

-   **国货之光：** 原生支持阿里云盘、115 网盘、百度网盘、123 云盘。扫码即连，几乎没有学习成本。
-   **刮削神速：** 同样是几千部电影，Infuse 可能要扫一天，VidHub 只要十几分钟，而且中文电影信息的识别率极高。
-   **价格厚道：** 相比 Infuse 的天价，VidHub 的买断价格非常亲民。

  

-   **痛点：**

-   **细节打磨中：** 在极少数超大 HDR 原盘的处理上，画质对比度与 Infuse 相比仍有微小差距。

  

-   **适合谁：** 资源都在网盘里、不想折腾 NAS、追求极致性价比的用户。

* * *

### 三、 功能主义的“瑞士军刀”：SenPlayer (森播放器)

**关键词：** 跳过片头、IPTV、全能选手。

SenPlayer 是一款非常“懂事”的播放器，它加入了很多大厂不屑于做、但用户极度需要的小功能。

-   **核心优势：**

-   **追剧神器：** 它是这几款里唯一完美支持“跳过片头片尾”的，看电视剧爽感倍增。
-   **双修达人：** 不仅能扫库看电影，还内置了极强的 IPTV 直播功能，甚至支持 8K 视频和 AV1 硬解。
-   **目录模式：** 如果你不想等海报墙刮削，直接进文件夹点开就播，效率极高。

  

-   **痛点：** UI 交互的精致程度相比 Infuse 略逊一筹。
-   **适合谁：** 重度追剧党、有看电视直播需求的用户。

* * *

### 四、 家庭影院的“数字大脑”：Emby

**关键词：** 媒体服务器、远程观看、多端同步。

把 Emby 和前三者对比其实有点“不公平”，因为 Emby 本质上是一个**服务端-客户端**体系。

-   **核心优势：**

-   **集中管理：** 你在一台电脑（NAS）上装好 Emby Server，所有设备登录账号就能看，播放进度、海报墙完全统一。
-   **远程转码：** 这是它最大的杀手锏。如果你在外出差，家里网速不够，Emby Server 会把 4K 电影实时转码成 720P 给你的手机播放，流畅不卡顿。

  

-   **痛点：** 设置门槛高，需要 24 小时开机的服务器，官方 App 播放性能一般（通常大家会用 Infuse 连 Emby）。
-   **适合谁：** 拥有 NAS 的重度玩家、想要把个人片库分享给亲友的人。

* * *

### 五、 总结与购买建议

为了方便大家“抄作业”，我总结了以下三个方案：

### 1\. 终极发烧方案（画质+管理）

**【Emby Server + Infuse】** 在 NAS 上用 Emby 整理资源，在 Mac/Apple TV 上用 Infuse 作为前端播放。这是目前 Apple 生态下画质最强、管理最爽的组合，没有之一。

### 2\. 简单省心方案（云盘直看）

**【VidHub】** 不想买 NAS，不想折腾网络。直接把阿里云盘/115 往里一塞，享受极速的海报墙和流畅的播放体验。

### 3\. 全能追剧方案（多功能）

**【SenPlayer】** 如果你既要看电影，又要看电视直播，还特别讨厌看电视剧的片头，选它准没错。

* * *

**最后附上安装小技巧：** 这些 App 在 Homebrew 都没有官方 Cask。如果你习惯命令行，可以先执行 `brew install mas`，然后通过以下命令一键安装：

```text
# Infuse
mas install 1136220934
# VidHub
mas install 1659622164
# SenPlayer
mas install 6443975850
# Emby
mas install 1560052907

```

**你的 Mac 里装的是哪一款？欢迎在评论区分享你的观影方案！**

* * *]]></description>
      
      <author>Admin</author>
      <pubDate>Sat, 02 May 2026 12:14:26 GMT</pubDate>
    </item>

    <item>
      <title><![CDATA[《纸牌屋》S1E3深度拆解：从“大桃子”到“工会战”，顶级政客如何处理危机？]]></title>
      <link>https://daichangyu.com/zh/blog/zhi-pai-wu-s1e3shen-du-chai-jie-cong-da-tao-zi-dao-gong-hui-zhihu-2033656529270874296</link>
      <guid isPermaLink="true">https://daichangyu.com/zh/blog/zhi-pai-wu-s1e3shen-du-chai-jie-cong-da-tao-zi-dao-gong-hui-zhihu-2033656529270874296</guid>
      <description><![CDATA[这是一篇为您深度定制的《纸牌屋》第一季第三集（Chapter 3）知乎解析。本集的主题是**“后院起火”与“零售政治”**，展现了弗兰克如何在处理地方琐事与国家法案之间进行高超的权力平衡。

![](/images/zhihu/zhi-pai-wu-s1e3shen-du-chai-jie-cong-da-tao-zi-dao-gong-hui-zhihu-2033656529270874296/e5ebe1830385.jpg)

* * *

## 《纸牌屋》S1E3深度拆解：从“大桃子”到“工会战”，顶级政客如何处理危机？

**导语：** 在第一集中，我们看到了弗兰克的野心；第二集中，我们看到了他的权谋；而到了第三集，导演将镜头拉回了弗兰克的老家——南卡罗来纳州第九选区。

这一集非常精彩地展示了一个残酷的现实：**哪怕你在华盛顿翻云覆雨，如果搞不定家乡那座“像屁股一样的水塔”，你的权力大厦也会瞬间崩塌。**

今天我们从四个维度，深度拆解这一集的政治逻辑。

* * *

### 一、 维度一：什么是“零售政治”？

**——为什么一个“大桃子”水塔能威胁到弗兰克的地位？**

这一集的核心危机是一个离奇的悲剧：一名少女因为一边开车看那个桃子形状的水塔（The Peachoid）一边发短信，结果出了车祸丧生。弗兰克的政敌立刻利用这件事攻击他。

-   **零售政治（Retail Politics）：** 在美国，政客不仅要在国会辩论，还要亲自下基层去握手、吊唁、处理路灯坏了或者水塔太丑这种琐事。这叫“零售”，因为你需要一票一票地去赢。
-   **后院不能起火：** 弗兰克虽然是国会大佬，但他的权力根基来源于他的选区。如果家乡选民觉得他“进城当官忘了本”，或者连个引发事故的水塔都管不好，他就会在下次选举中落马。**丢了选区，就等于丢了进入国会的入场券，那他在华盛顿的所有权势都会归零。**

* * *

### 二、 维度二：危机公关的“降维打击”

**——弗兰克如何用一段祷告平息愤怒？**

弗兰克回到老家处理死者父母的愤怒，这一段是教科书级的公关案例：

1.  **共情先行：** 他没有谈法律责任，而是谈自己早逝的父亲。他把自己从一个“高高在上的议员”降到了“同样失去亲人的普通人”。
2.  **宗教的武器化：** 在教堂的那场演讲是全集的高光。他不仅没有回避上帝为什么让悲剧发生，反而通过解构“仇恨”和“痛苦”，成功将死者父母的愤怒转化为了对上帝的敬畏和对他个人的理解。
3.  **利益交换：** 他承诺以少女的名字建立奖学金，并将水塔改为“纪念性建筑”。这在政治上叫**“化干戈为玉帛”**——把一个负面资产变成了他的个人政治遗产。

* * *

### 三、 维度三：华盛顿的真正硬骨头

**——教师工会与马蒂·斯宾内拉的登场**

在老家救火的同时，弗兰克在华盛顿遇到了真正的对手：**教育改革的最大阻力——教师工会。**

-   **马蒂·斯宾内拉（Marty Spinella）：** 此人是工会领袖，他不像政客那样讲究体面，他手里握着数百万教师的选票和庞大的政治献金。
-   **权力的博弈：** 弗兰克试图利诱马蒂，但马蒂软硬不吃。这预示着教育法案的推进将进入“绞肉机”阶段。弗兰克意识到，对付这种硬汉，温和的游说无效，必须制造更大的矛盾来逼对方就范。

* * *

### 四、 维度四：克莱尔的“权力修剪”

**——净水计划（CWI）的大裁员**

这一集里，弗兰克的妻子克莱尔展现了不亚于丈夫的冷酷。她为了给新招募的“战略人才”腾位置和经费，直接裁掉了公司一半的老员工。

-   **冷酷的理性：** 克莱尔辞退那名跟了她多年的老主管时，没有任何温情。在她的逻辑里：**如果你的价值不能支撑我下一阶段的野心，那你就是必须被剪掉的枯枝。**
-   **互为镜像：** 这一段与弗兰克在老家“温情脉脉”的公关形成了鲜明对比。弗兰克在台前演戏，克莱尔在幕后挥刀。这夫妻俩一个负责“统战”，一个负责“清洗”，配合得天衣无缝。

* * *

### 五、 核心细节解析：那个“桃子水塔”到底喻指什么？

水塔在剧中被反复嘲讽“看起来像个大屁股”。这其实是一个隐喻：

1.  **权力的虚荣：** 政客喜欢搞这种地标建筑来彰显政绩，却往往华而不实。
2.  **权力的脆弱：** 一个微小的偶然事件（少女发短信），就能让这个宏大的地标变成杀人的利器。
3.  **弗兰克的生存哲学：** 面对嘲讽和危机，弗兰克没有拆掉它，而是重新定义了它。这就是他的生存之道——**如果不美观，那就给它赋予神圣性。**

* * *

### 六、 总结：顶级政客的生存法则

第三集告诉了我们关于权力的三个真相：

1.  **所有的政治都是地方政治：** 管不好老家的人，管不好选区，你在华盛顿的声音再大也是虚火。
2.  **痛苦是可以被利用的资源：** 无论是死者父母的痛苦，还是被裁员工的痛苦，在权力眼中都是可以交换的筹码。
3.  **必须随时准备两线作战：** 弗兰克在南卡罗来纳州演“好人”，在华盛顿准备当“恶棍”。这种人格的快速切换，是顶级政客的基本功。

* * *

**知乎提问引导：**

-   如何看待克莱尔大面积裁员的行为？是必要的转型还是冷血的过河拆桥？
-   弗兰克在教堂的演讲中，真的有那一刻是真诚的吗？
-   如果那对父母坚持起诉，弗兰克的政治生涯会终结吗？

**如果你喜欢这种一集一拆解的硬核内容，请关注本专栏。下一期我们将分析：弗兰克如何利用“酒驾议员”罗素，布下第一颗最重要的棋子。**]]></description>
      
      <author>Admin</author>
      <pubDate>Fri, 01 May 2026 13:19:48 GMT</pubDate>
    </item>

    <item>
      <title><![CDATA[《纸牌屋》S1E4深度拆解：没有永远的朋友，只有捏在手里的软肋]]></title>
      <link>https://daichangyu.com/zh/blog/zhi-pai-wu-s1e4shen-du-chai-jie-mei-you-yong-yuan-de-peng-yo-zhihu-2033655612026958530</link>
      <guid isPermaLink="true">https://daichangyu.com/zh/blog/zhi-pai-wu-s1e4shen-du-chai-jie-mei-you-yong-yuan-de-peng-yo-zhihu-2033655612026958530</guid>
      <description><![CDATA[这是一篇为您深度定制的《纸牌屋》第一季第四集（Chapter 4）解析。这一集是全剧的分水岭，弗兰克正式开始了**“以小博大”**的博弈，展现了政治中最为黑暗也最迷人的一面：**利益交换与筹码控制。**

  

* * *

## 《纸牌屋》S1E4深度拆解：没有永远的朋友，只有捏在手里的软肋

**导语：** 如果说前三集是在布线，那么第四集就是弗兰克正式收网的开始。在这一集里，教育法案遭遇了空前的阻力，弗兰克不仅要面对强大的工会，还要应付党内大佬的背叛。

但他通过这一集告诉我们：**政治不是请客吃饭，政治是寻找那个能让对手感到剧痛的“支点”。**

* * *

### 一、 维度一：顶级“猎人”如何驯服猎物？

**——彼得·罗素（Peter Russo）的彻底沦陷**

本集最令人心碎也最硬核的逻辑，在于弗兰克对宾夕法尼亚州众议员**彼得·罗素**的操控。

1.  **致命的软肋：** 彼得酒驾、招妓、吸毒的污点被弗兰克死死按住。在政治中，**一个有污点的人，比一个纯洁的人更有价值**，因为他绝对听话。
2.  **残酷的选择：** 弗兰克要求彼得支持一份会让他家乡选民（造船厂工人）失业的法案。这对政客来说是自杀。
3.  **PUA式的控制：** 弗兰克先给彼得一点希望（承诺保护造船厂），然后再亲手撕碎它，逼迫彼得在“政治死亡”和“灵魂出卖”之间选一个。

**职场启示：** 当一个上司突然帮你掩盖了一个巨大错误时，别忙着感激。他可能正在把你变成一个**“一次性消耗品”**。最好的防守是永远不要让别人手里握着你的“核武器按钮”。

* * *

### 二、 维度二：游说集团与“影子权力”

**——雷米·丹顿（Remy Danton）的博弈**

这一集里，弗兰克的老下属、现在的金牌游说客**雷米**正式展露锋芒。他代表的是能源巨头 **SanCorp**。

-   **政治的“燃料”：** 钱。游说客不直接立法，但他们控制着竞选资金。
-   **师徒对决：** 雷米曾是弗兰克的幕僚长，他太了解弗兰克的套路。这种“前任下属变身金主代表”的关系，完美诠释了华盛顿的旋转门（Revolving Door）机制：**今天在政府立法的官员，明天就是拿高薪的游说客。**
-   **博弈逻辑：** 弗兰克拒绝了雷米的捐款。为什么？因为**一旦拿了钱，你就成了别人的工具；如果不拿钱，你就能让别人为了讨好你而付出更多。** 弗兰克在玩一种更高级的欲望。

![](/images/zhihu/zhi-pai-wu-s1e4shen-du-chai-jie-mei-you-yong-yuan-de-peng-yo-zhihu-2033655612026958530/f91532fa0cb0.jpg)

* * *

### 三、 维度三：党内的“宫斗剧”

**——众议院议长与多数党领袖的博弈**

教育法案推进不下去，不仅是因为工会，还因为党内大佬**鲍勃·博查（Bob Birch）**和**特里·切诺（Terry Womack）**各怀鬼胎。

1.  **制造混乱：** 弗兰克故意泄露消息，让议长处于尴尬境地。
2.  **分而治之：** 他通过牺牲彼得·罗素所在的造船厂利益，去换取非裔党团领袖特里的支持。
3.  **结果导向：** 弗兰克不在乎牺牲谁，他在乎的是如何通过重新排列组合，让那些反对他的人不得不坐到桌上来。

* * *

### 四、 维度四：克莱尔的自由与枷锁

**——亚当·加洛韦（Adam Galloway）的出现**

这一集展示了克莱尔在冷酷女强人之外的另一面。她去了纽约，去见那个搞摄影的艺术家亚当。

-   **权力的透气孔：** 克莱尔与弗兰克的婚姻是权力的盟约，而亚当代表的是**“被放弃的自我”**。
-   **残忍的回归：** 尽管亚当能给她温情，但克莱尔最终还是选择了回到华盛顿。因为她清楚，艺术家的自由是虚幻的，只有掌握在手中的权力才是真实的。
-   **镜像关系：** 弗兰克在华盛顿操纵彼得的肉体，克莱尔在纽约修剪自己的灵魂。这对夫妻都在为了更大的目标进行残酷的自我阉割。

* * *

### 五、 核心金句解析：关于“狮子”与“将军”

弗兰克在这一集有一句名言：

> **“我从不怀疑他的勇气，但我怀疑他的判断。一个将军如果只知道冲锋，那他迟早会死在自己的刀下。”**

这指的就是彼得·罗素。彼得试图用自毁的方式去拯救家乡，但在弗兰克看来，这极其幼稚。在权力的游戏中，**“善良”和“冲锋”往往是低效的，唯有“忍耐”和“交易”才能通向胜利。**

* * *

### 六、 总结：第四集告诉我们的政治真相

1.  **价值对等：** 你想保住你的职业生涯（彼得），就必须交出你的政治筹码（造船厂）。
2.  **借刀杀人：** 弗兰克通过毁掉一个人的家乡，换取了整个党派对教育法案的支持。
3.  **不要相信所谓的“避风港”：** 无论是在纽约的艺术家公寓，还是在南卡的老家，权力的触角无处不在。

* * *

**知乎式提问引导：**

-   如何评价弗兰克对彼得·罗素的这种“极限施压”？
-   雷米·丹顿这种人，在现实的美国政坛里权力到底有多大？
-   克莱尔为什么最后拒绝了亚当？她是真的不爱他吗？

**如果你觉得解析到位，请点赞收藏。第五集我们将看到：当法案进入投票阶段，弗兰克如何处理那个已经崩溃的、处于爆发边缘的彼得·罗素。**

* * *

### **Markdown 发布排版建议：**

-   **重点标注：** 所有的**利益交换**部分建议加粗，这是本集的灵魂。
-   **情感对比：** 建议将彼得·罗素的绝望和弗兰克的冷静排在一起，形成视觉和心理的强烈对比。
-   **引用说明：** 在解析雷米的部分，可以简单科普一下美国“游说集团（Lobbying）”的运作逻辑。]]></description>
      
      <author>Admin</author>
      <pubDate>Fri, 01 May 2026 13:17:48 GMT</pubDate>
    </item>

    <item>
      <title><![CDATA[纸牌屋S1E2 -- 权力游戏的教科书：为什么下木总统能用一个“教育法案”玩残所有人？]]></title>
      <link>https://daichangyu.com/zh/blog/zhi-pai-wus1e2-quan-li-you-xi-de-jiao-ke-shu-wei-shen-me-xia-zhihu-2033621895694783177</link>
      <guid isPermaLink="true">https://daichangyu.com/zh/blog/zhi-pai-wus1e2-quan-li-you-xi-de-jiao-ke-shu-wei-shen-me-xia-zhihu-2033621895694783177</guid>
      <description><![CDATA[![](/images/zhihu/zhi-pai-wus1e2-quan-li-you-xi-de-jiao-ke-shu-wei-shen-me-xia-zhihu-2033621895694783177/4278e4db2d78.jpg)

## 权力游戏的教科书：为什么下木总统能用一个“教育法案”玩残所有人？

**导语：** 很多人看《纸牌屋》第二集时会产生疑惑：弗兰克（Frank Underwood）作为党鞭，不是应该帮总统干活吗？为什么他要故意泄露教育法案？那个白发苍苍的老议员唐纳德代表的“左翼”到底触碰了谁的蛋糕？为什么一个草案泄露就能演变成足以毁掉政客生涯的“丑闻”？

今天，我们拆开《纸牌屋》的第二层皮，看看美国政坛背后那台血淋淋的割肉机。

* * *

### 一、 核心背景：当“董事会”决定给“总经理”挖坑

在上一篇文章中我们讲过，弗兰克没当上**国务卿（外交部长）**，被留在了**国会（董事会）**当苦力。

第二集的主线是总统交给弗兰克一个任务：**100天内通过《教育改革法案》**。 总统的想法很单纯：你是国会大佬（党鞭），你负责写，写完利用你的影响力让大家投票通过。

但弗兰克心里想的是：**既然你过河拆桥，我就让你这100天变成职业生涯的噩梦。**

* * *

### 二、 深度解析：美国的“左”到底在争什么？

剧中出现了一个关键人物：**唐纳德·布莱斯（Donald Blythe）**。他是弗兰克名义上的拍档，也是典型的“激进左翼”。

### 1\. 什么是剧中的“左”？

在美国民主党内部，“左”代表的是**理想主义**和**大政府**。唐纳德这类人的主张通常包括：

-   **教育公平：** 联邦政府应该出更多的钱，管更多的事。
-   **工会至上：** 教师工会的利益神圣不可侵犯，不能随便开除老师。
-   **去竞争化：** 反对给学校排名，反对优胜劣汰。

### 2\. 为什么弗兰克要用“左”来杀人？

弗兰克深知：**极端的理想主义在政治上就是自杀。** 他故意让唐纳德去写草案，其实就是给这头“老黄牛”一根胡萝卜，引诱他把那些最激进、最不切实际的思想全写进去。

* * *

### 三、 丑闻复盘：一个泄密的草案，为何能杀人？

弗兰克把唐纳德那份还没定稿的、极其激进的草案，通过女记者佐伊捅给了媒体。

![](/images/zhihu/zhi-pai-wus1e2-quan-li-you-xi-de-jiao-ke-shu-wei-shen-me-xia-zhihu-2033621895694783177/abf731bcc3ca.jpg)

### 1\. 为什么这是“丑闻”？

在普通人看来，泄密只是违规。但在政治家看来，这是**政治自杀**。

-   **激怒了中间选民：** 草案里那些“联邦政府接管教育”的内容，让很多渴望地方自治的美国民众感到恐慌：_“政府又要来洗脑我们的孩子了？”_
-   **得罪了金主和利益集团：** 草案中不成熟的条款可能同时得罪了工会和共和党。
-   **让总统失信：** 总统刚上任，本该展示稳健的一面，结果爆出一个“极左”方案。外界会认为：**这个新总统被激进派绑架了。**

![](/images/zhihu/zhi-pai-wus1e2-quan-li-you-xi-de-jiao-ke-shu-wei-shen-me-xia-zhihu-2033621895694783177/8c1454e78a94.jpg)

### 2\. 弗兰克的“一石三鸟”毒计

-   **铲除异己：** 唐纳德成了泄密的罪魁祸首，直接被踢出局，还得对弗兰克感恩戴德（因为弗兰克表面上在保护他）。
-   **建立依赖：** 总统陷入公关危机，焦头烂额。这时候弗兰克跳出来说：“别慌，我来收拾残局。” 总统从此对他产生了病态的依赖。
-   **掌控规则：** 踢走了唐纳德，弗兰克就可以按照自己的意志重新编写法案，把教育改革变成自己交换权力的筹码。

* * *

### 四、 职场启示：如何识别弗兰克式的陷阱？

《纸牌屋》第二集其实讲了一个非常残酷的职场道理：**“捧杀”。**

1.  **给你不属于你的光环：** 弗兰克让唐纳德牵头法案（看似重用，实则架火烤）。
2.  **放任你的弱点：** 弗兰克明知唐纳德的思想太激进，却一直鼓励他“坚持自我”（放任对方自杀）。
3.  **精准引爆：** 在你最得意、最没有防备的时候，把你的内部弱点公之于众。

* * *

### 五、 总结：国会老手的反击

回到我们最初的主题：**国会 vs 国务院。**

总统本想让弗兰克在国会乖乖当个“服务员”，协助行政分支（国务院等部门）推动政策。但弗兰克用第二集的表现告诉总统：**在国会这个地盘上，我才是定规矩的人。**

他不需要当国务卿去搞外交，他只需要在国会的大厦里抖一抖烟灰，整个白宫都要跟着地震。

**下一期预告：** 当权力开始稳固，弗兰克又是如何利用一个“酒驾”的草根议员，完成更深层的布局？欢迎关注，我们接着拆解。

* * *

-   **你认为唐纳德这样的理想主义者在政坛有生存空间吗？**
-   **如果你是总统，你会如何防范弗兰克这样的“党鞭”？**

欢迎在评论区留下你的看法。]]></description>
      
      <author>Admin</author>
      <pubDate>Fri, 01 May 2026 11:12:41 GMT</pubDate>
    </item>

    <item>
      <title><![CDATA[看不懂《纸牌屋》第一集？那是你没搞懂美国“国会”和“国务院”的区别]]></title>
      <link>https://daichangyu.com/zh/blog/kan-bu-dong-zhi-pai-wu-di-yi-ji-na-shi-ni-mei-gao-dong-mei-g-zhihu-2033596199819813616</link>
      <guid isPermaLink="true">https://daichangyu.com/zh/blog/kan-bu-dong-zhi-pai-wu-di-yi-ji-na-shi-ni-mei-gao-dong-mei-g-zhihu-2033596199819813616</guid>
      <description><![CDATA[![](/images/zhihu/kan-bu-dong-zhi-pai-wu-di-yi-ji-na-shi-ni-mei-gao-dong-mei-g-zhihu-2033596199819813616/af57a787f3cd.jpg)

导语： 很多人刷《纸牌屋》（House of Cards）第一集时，会被主角弗兰克（Frank Underwood）那种阴冷、愤怒的情绪震慑。他费尽心机帮总统赢了大选，结果总统没让他当上“国务卿”，他转头就开始了毁灭性的复仇。

很多政治小白会纳闷：他不已经是国会的“巨头”了吗？没当上国务卿至于这么大火气吗？

其实，这里面不仅涉及美国权力的核心逻辑，还藏着一个中文翻译带来的巨大误解。今天我们一次性拆解清楚。

一、 翻译的“大坑”：此“国务院”非彼“国务院”

首先，我们要消除中文语境带来的第一直觉误导。

-   中国的国务院： 是中央人民政府，是国家的最高行政机关，管辖所有的部委（如外交部、公安部、财政部等）。
-   美国的国务院（Department of State）： 虽然名字也叫“国务院”，但它的职能其实等同于**“外交部”**。

划重点： 美国国务卿（Secretary of State）本质上就是外交部长。但他不仅是内阁成员之首，还是总统的第一顺位接班人（第四顺位），所以地位极其显赫，是总统处理国际事务的“头号军师”。

二、 权力架构：董事会 vs 总经理

要理解国会和国务院的区别，你可以把美国政府想象成一家大公司：

1.  国会 (Congress) = 董事会  
    

-   身份： 他们是代表股东（全美选民）的。
-   权力： 负责制定公司的家规（法律），决定公司的钱怎么花（审批预算）。
-   地位： 他们是独立于CEO（总统）的。董事会不仅不听CEO的，甚至可以调查、弹劾CEO。

  

1.  国务院 (State Dept) = 外交与公关部  
    

-   身份： 它是CEO（总统）手下的一个核心职能部门。
-   权力： 负责出门谈生意、搞关系、维护品牌形象（处理外交事务）。
-   地位： 从属于总统。国务卿是总统提名的，必须听总统的指令。

  

三、 深度拆解：为什么《纸牌屋》下木总统的怨气这么大？

在第一集里，弗兰克原本的职位是国会的**“多数党党鞭”（Majority Whip）**。

1.  他原本的职位（磨坊里的驴）

作为党鞭，他是“董事会”里的纪律检查员。他的活儿最脏最累：要威逼利诱、软硬兼施地让几百号议员听话，确保总统想要的法案能通过。

-   弗兰克的感受： 我在这个位置干了22年，每天都在和几百个人磨嘴皮子、交换利益，这叫“幕后苦力”。

1.  他想要的职位（舞台上的星）

他想当国务卿。

-   诱惑点： 走出吵闹的国会山，代表国家在国际舞台上发声，拥有专属专机，手握真正的行政外交大权，且离白宫权力核心仅一步之遥。

1.  被“放鸽子”的政治羞辱

总统在大选前承诺给他国务卿的位置，选后却反悔了，理由竟然是：“你在国会里拉磨拉得太好了，我们需要你留在那里继续帮我们干苦力。”

这种**“过河拆桥 + 职业天花板”**的羞辱，是弗兰克黑化的导火索。正如他在剧中的名言：

“痛苦分两种。一种让你变得更强，另一种毫无意义，只是让你徒增折磨。我没耐心受这种无意义的苦。”

四、 核心区别对照表（防混淆指南）

维度

国会 (Congress)

国务院 (Department of State)

所属分支

立法分支（独立权力）

行政分支（总统下属）

首脑名称

众议院议长 / 参议院领袖

国务卿

核心职能

定规矩、管钱袋子、监督政府

搞外交、办实事、执行政策

权力来源

选民直接投票选举

总统任命（需参议院通过）

形象比喻

规则制定者、冷酷的监工

总统的传声筒、大外交官

五、 它们之间怎么“打架”？（制衡逻辑）

理解了区别，你就能看懂剧中更深层的权谋：

1.  钱的制衡： 国务卿（国务院）想援助某个国家，必须低头去向国会要预算。如果弗兰克在国会里使坏，国务院一分钱也拿不到。
2.  人的制衡： 总统任命新的国务卿，必须经过国会（参议院）的面试投票。如果国会看这个人不顺眼，总统的任命就是废纸一张。

总结一下： 弗兰克之所以可怕，是因为他深谙国会的运作机理。当他没能当上国务院的老大时，他决定利用自己手中**“定规矩”和“管预算”**的权力，反向锁死白宫和国务院的喉咙。

这就是《纸牌屋》的开端：一个被留在“董事会”里的资深包工头，开始疯狂报复那个过河拆桥的CEO。

如果你觉得这篇科普帮你理清了思路，欢迎点赞、收藏、转发！ 关于美国政治或美剧背景，你还有哪些想了解的？欢迎在评论区留言讨论。]]></description>
      
      <author>Admin</author>
      <pubDate>Fri, 01 May 2026 09:43:28 GMT</pubDate>
    </item>

    <item>
      <title><![CDATA[Vmware Fusion win11分辨率设置MacOS]]></title>
      <link>https://daichangyu.com/zh/blog/vmware-fusion-win11fen-bian-l-she-zhimacos-zhihu-2030727323260032019</link>
      <guid isPermaLink="true">https://daichangyu.com/zh/blog/vmware-fusion-win11fen-bian-l-she-zhimacos-zhihu-2030727323260032019</guid>
      <description><![CDATA[今天在MacOS安装了最新的Vmware Fusion 丝滑的安装了win11，但是发现分辨率只有1024\*768，搜索网上的教程和AI问答，不尽人意，最后折腾发现需要安装内置的工具VMware Tools 找了半天，它在上面Mac菜单栏的其中一个里……

![](/images/zhihu/vmware-fusion-win11fen-bian-l-she-zhimacos-zhihu-2030727323260032019/93a881f50c27.jpg)]]></description>
      
      <author>Admin</author>
      <pubDate>Thu, 23 Apr 2026 11:30:43 GMT</pubDate>
    </item>

    <item>
      <title><![CDATA[什么是跨域？]]></title>
      <link>https://daichangyu.com/zh/blog/shen-me-shi-kua-yu-zhihu-2030692651218027705</link>
      <guid isPermaLink="true">https://daichangyu.com/zh/blog/shen-me-shi-kua-yu-zhihu-2030692651218027705</guid>
      <description><![CDATA[今天看知乎上解释什么是跨域，没有写的通俗易懂的，于是自己结合AI写了一个。

本文适用对象：纯小白

* * *

🍪 什么是跨域？（小白极速入门版）

既然是小白，那我们完全抛弃程序员的专业术语，用**“邻里关系”**和**“保安”**来给你打个比方。

* * *

### 1️⃣ 什么是跨域？（保安大爷的盘查）

想象你住在北京的一个小区，名字叫**“西郊壹号”**。

-   **🏠 你的家（前端）**：在这个小区里，你住在 **A 栋 101 室**。
-   **🍫 你的零食库（后端/服务器）**：也在这个小区，是 **B 栋 202 室**。

平时你在家想吃零食，直接去 B 栋 202 拿就行，保安大爷认识你，知道你是自家人，这叫**“同源”**，随便进。

**突然有一天：** 你想吃点新鲜的，听说隔壁**“东郊大院”**的 **C 栋 303 室** 有好吃的蛋糕。你跑过去想推门进去拿，这时候，门口的**保安大爷（浏览器）**一把拦住了你：

> 👮‍♂️ **保安：** “站住！你是西郊壹号的，凭什么来东郊大院拿东西？这叫跨域，不准进！”

**📝 划重点**

> **跨域**：浏览器就像这个保安，为了安全，它规定：**除非对方明确同意，否则你不能随便拿别家（不同域名/协议/端口）的东西。**

* * *

### 2️⃣ 为什么要拦着你？（为了防贼）

你可能会觉得这保安多管闲事，但如果没有他，世界就乱套了。

想象一下：如果你刚登录了**网上银行**（西郊壹号），这时你又打开了一个**中奖钓鱼网站**（东郊大院）。 如果没这个保安，那个**钓鱼网站**就可以偷偷潜入你的**银行页面**，把你的登录信息（Cookie）偷走，然后冒充你把钱转光。

🛡️ **保安（浏览器）的存在，就是为了确保：只有你自己家的东西，你才能随便碰。**

* * *

### 3️⃣ 那怎么才能拿到别家的东西？（三种解决办法）

有时候我们确实需要去别人家拿东西（比如你的网页需要去天气预报的服务器拿数据），这时候有几种办法：

### 🛠️ 方法 A：主人出门打招呼（CORS - 最常用的正规手段）

你（前端）去东郊大院（别的服务器）拿蛋糕。东郊大院的主人提前跟保安交待了：_“只要是西郊壹号的人来拿，我都给，让他们进！”_ 保安大爷查了一下名单，发现你确实在白名单上，就放你进去了。

-   💡 _专业术语：服务器在响应头里加个 `Access-Control-Allow-Origin`。_

### 🛵 方法 B：找个中间人代买（Proxy/代理 - 程序员最爱用）

你怕保安拦，你就不亲自去了。你找了一个**跑腿小哥（开发服务器/Nginx）**。小哥先到你家，然后转头去东郊大院帮你把蛋糕买回来送到你家。 **重点来了**：保安大爷只拦“普通邻居”，不拦“职业跑腿的服务器”。服务器和服务器之间说话，是没有保安管的。

-   💡 _专业术语：前端请求自己的服务器，服务器再去请求目标服务器。_

### 🕳️ 方法 C：钻窗户（JSONP - 老旧过时的办法）

东郊大院的窗户没关严，你把写着“我要蛋糕”的纸条塞进去，对方从窗户里把蛋糕扔给你。这种办法只能干点简单的活，现在已经很少有人用了。

-   💡 _专业术语：利用 `<script>` 标签不受同源策略限制的漏洞，且只支持 `GET` 请求。_

* * *

### 📌 总结一下

-   🤝 **跨域** = 你的网页想去拿**别人家**（不同域名）的东西。
-   🛡️ **同源策略** = 浏览器派出的**保安**，为了安全不让你乱拿。
-   📏 **判断标准** = 只要“协议、域名、端口”这三个有一个对不上，保安就认为你是跨域。
-   🔑 **解决方案** = 要么对方**允许**你拿（CORS），要么找个**中间人**帮你拿（代理）。]]></description>
      
      <author>Admin</author>
      <pubDate>Thu, 23 Apr 2026 09:03:00 GMT</pubDate>
    </item>

    <item>
      <title><![CDATA[IEC 60870-5-102 与 IEC 60870-5-104 规约区别]]></title>
      <link>https://daichangyu.com/zh/blog/iec-60870-5-102-yu-iec-60870-5-104-gui-yue-qu-bie-zhihu-2029936240728995201</link>
      <guid isPermaLink="true">https://daichangyu.com/zh/blog/iec-60870-5-102-yu-iec-60870-5-104-gui-yue-qu-bie-zhihu-2029936240728995201</guid>
      <description><![CDATA[本文适用读者：基本了解104协议

* * *

  

这是一个关于 **IEC 60870-5-102** 与 **IEC 60870-5-104** 规约区别的详细整理文档，涵盖了从基本概念、通信架构到报文交互及 ASDU 细节的全维度对比。

* * *

## IEC 102 与 IEC 104 通信规约深度对比手册

### 1\. 核心定位与应用场景

维度

IEC 60870-5-102 (简称 102)

IEC 60870-5-104 (简称 104)

全称

电力系统电能累计量传输配套标准

采用标准传输协议子集的网络访问配套标准

核心业务

“抄表”：专门用于电能量计费系统。

“监控”：用于变电站调度自动化 (SCADA)。

主要数据

历史/实时电能量累计值（峰谷平电量）。

四遥数据（遥信、遥测、遥控、遥调）。

实时性

较低。通常分钟级或按天定时抄收。

极高。支持毫秒级变位上报（SOE）。

* * *

### 2\. 通信架构与协议栈

### 2.1 IEC 102：增强性能架构 (EPA)

-   **模型：** 遵循 OSI 三层模型（物理层、数据链路层、应用层）。
-   **物理媒介：** 早期原生设计为串行接口（RS-232/485），使用异步字节传输。
-   **帧格式：** 采用 **FT1.2 帧格式**（包含起始符 `68H` 或 `10H`，结束符 `16H`，以及和校验 Checksum）。

### 2.2 IEC 104：网络访问架构

-   **模型：** 将应用层直接映射到 **TCP/IP 协议栈**。
-   **物理媒介：** 以太网（光纤、网线）。
-   **标准端口：** TCP **2404**。
-   **帧格式：** 采用 **APDU 结构**（以 `68H` 开头，靠长度控制，无校验和与结束符，由 TCP 层保证可靠性）。

* * *

### 3\. 报文交互机制

### 3.1 交互模式

-   **IEC 102 (一问一答)：**

-   属于**非平衡传输**（主从模式）。
-   子站（电表）从不主动说话。主站发送“召唤”请求，子站返回对应响应。
-   **分帧逻辑：** 如果数据较长，主站需发送“请求下一帧”，子站配合 **FCB (帧计数位)** 翻转来防止丢包或重复。

  

-   **IEC 104 (主动上报)：**

-   属于**平衡传输**（客户端-服务器模式）。
-   **启动：** 建立 TCP 连接后，通过 **U 帧 (STARTDT)** 激活传输。
-   **突发上报：** 一旦发生开关动作或数值超过阈值，子站**立即主动发送** I 帧，无需主站轮询。
-   **确认机制：** 采用**滑动窗口**机制，通过 **S 帧** 确认接收到的序列号，支持连续发送。

  

### 3.2 初始化流程对比

-   **102：** 链路请求 -> 响应状态 -> 复位链路 -> 开始召唤。
-   **104：** TCP 三次握手 -> U 帧启动 (STARTDT) -> 总召唤 (Type 100)。

* * *

### 4\. ASDU (应用服务数据单元) 深度解析

ASDU 是规约中真正承载业务数据的核心部分。

### 4.1 数据侧重点

-   **IEC 102 ASDU：**

-   **核心 ID：** Type 11（召唤特定时段电量）、Type 7（带时戳累计量）。
-   **逻辑：** 类似于“数据库查询”。报文中会包含**起始时间**和**结束时间**。
-   **费率处理：** ASDU 中包含不同费率（尖、峰、平、谷）的电量描述。

  

-   **IEC 104 ASDU：**

-   **核心 ID：** Type 1（遥信）、Type 13（浮点数遥测）、Type 45（遥控）、Type 30（带毫秒时戳的 SOE）。
-   **品质描述：** 每个数据自带品质位（IV-无效、NT-非当前、SB-取代、BL-封锁）。

  

### 4.2 时间戳的区别

-   **102 的时戳：** 代表**“结算点”**。例如：“这是 4 月 21 日 14:00 的结算电量”。
-   **104 的时戳：** 代表**“事件瞬时”**。例如：“断路器在 14:00:00.123 毫秒发生了跳闸”。

* * *

### 5\. 总结对照表

特性

IEC 60870-5-102

IEC 60870-5-104

行业别称

电能规约 / 抄表规约

网络远动规约 / 调度规约

传输层

串行/链路层 (FT1.2)

TCP/IP (端口 2404)

发起权

必须由主站发起 (一问一答)

双向发起 (子站突发主动上报)

可靠性靠什么

FCB 翻转 + 和校验 (CS)

TCP 重传 + 104 滑动窗口序列号

数据内容

累计值、历史时段电量

实时开关状态、模拟量测量、遥控控制

报文结尾

有结束符 16H

无结束符

ASDU 类型示例

Type 11 (读特定时段历史记录)

Type 30 (带毫秒时戳的变位信息)

* * *

**结论：**

-   如果你需要开发**电能计费系统**、统计用电量，请遵循 **IEC 102**。
-   如果你需要开发**变电站监控系统**、实现自动化调度和远程开关控制，请遵循 **IEC 104**。]]></description>
      
      <author>Admin</author>
      <pubDate>Tue, 21 Apr 2026 06:56:20 GMT</pubDate>
    </item>

    <item>
      <title><![CDATA[什么是jemalloc]]></title>
      <link>https://daichangyu.com/zh/blog/shen-me-shijemalloc-zhihu-2025577647720121751</link>
      <guid isPermaLink="true">https://daichangyu.com/zh/blog/shen-me-shijemalloc-zhihu-2025577647720121751</guid>
      <description><![CDATA[你好！欢迎来到 C++ 的世界。要把 **jemalloc** 讲清楚，我们不需要一上来就背代码，我们可以用一个**生活中的例子**来理解。

* * *

### 1\. 什么是“内存分配器” (Memory Allocator)？

想象你在经营一家巨大的**物流仓库**：

-   **内存**：就是仓库里的货架空间。  
    
-   **你的程序**：就是不断进货、出货的客户。  
    
-   **内存分配器**：就是仓库的**管理员**。  
    

当你的 C++ 程序写下 new 或者 malloc 时，就像是在喊：“管理员，给我找个 10 平方米的地方放货！”当程序运行结束调用 delete 或 free 时，就是在喊：“货走啦，这块地空出来了！”

**默认管理员 (ptmalloc)**：  
Windows 或 Linux 系统自带一个默认的管理员。它干活还行，但在某些极端情况下（比如几千个客户同时进货，或者货物大小千奇百怪），它会变得很慢，或者让仓库堆得乱七八糟。

**高级管理员 (jemalloc)**：  
jemalloc 就是一个“金牌高级管理员”。它最初是为 FreeBSD 操作系统开发的，后来因为表现太出色，被 Facebook（现在的 Meta）拿去大规模使用。

* * *

### 2\. jemalloc 到底牛在哪里？

既然有了默认的管理员，为什么要换成 jemalloc？它主要解决了两个令人头疼的问题：

### (1) 解决“多个人抢位置”的问题 (多线程并发)

-   **默认情况**：如果你的 C++ 程序开了 100 个线程，每个线程都要申请内存，默认管理员可能只有一个“登记本”，大家得排队领地盘，效率极低。  
    
-   **jemalloc**：它给每个线程分配了独立的小摊位（称为 **Arena**）。线程之间互不干扰，大家各领各的，速度极快。  
    

### (2) 解决“仓库碎渣”的问题 (内存碎片)

-   **默认情况**：如果一个 10 平方米的空间，被你东挖一块、西挖一块，最后剩下的全是 0.1 平方米的小洞。虽然总数够 10 平米，但你想放个 2 平米的东西时，却发现塞不进去了。这就叫**内存碎片**。  
    
-   **jemalloc**：它非常死板且聪明。它把空间预先分成了各种“标准规格”（比如 8字节、16字节、32字节...）。你申请多大，它就去对应的规格区拿。就像超市里整齐的货架，极大地减少了碎片的产生。  
    

* * *

### 3\. C++ 使用 jemalloc 有什么好处？

1.  **省内存**：因为它处理碎片的能力强，长期运行的大程序（比如数据库、游戏服务器）不会出现“明明没干啥，内存却越占越多”的情况。  
    
2.  **跑得快**：在多核 CPU 环境下，它能显著提高程序申请/释放内存的速度。  
    
3.  **调试方便**：它自带强大的**内存分析工具 (Profiling)**。你可以轻松查出：到底是哪一行代码偷偷占用了几百 MB 的内存没释放。  
    

* * *

### 4\. 怎么在 C++ 里用它？（小白版操作）

好消息是：**你几乎不需要改动任何 C++ 代码！** 你不需要把 new 改掉。

通常有两种用法：

### 方法 A：最简单的“暴力”用法 (无需重新编译)

在 Linux 下，你只需要在启动程序前加一个环境变量：

code Bashdownloadcontent\_copy  
expand\_less  
export LD\_PRELOAD=/usr/lib/libjemalloc.so ./your\_cpp\_program  

这就相当于强行把原来的“平庸管理员”开除了，换成了 jemalloc 上岗。

### 方法 B：在编译时链接

在编译你的 C++ 项目时，链接上 jemalloc 库：

code Bashdownloadcontent\_copy  
expand\_less  
g++ main.cpp -o my\_app -ljemalloc  

* * *

### 5\. 我什么时候该用它？

作为小白，你不需要在每个小练习里都用它。但在以下场景，你应该想起它：

-   **开发服务器端程序**：比如 Web 服务器、游戏后台、分布式系统。  
    
-   **处理大数据**：程序需要频繁地创建和销毁大量对象。  
    
-   **发现程序内存泄漏**：想利用 jemalloc 的 Profiling 功能查内存去向。  
    
-   **多线程重度用户**：程序里开了几十个线程疯狂工作。  
    

### 总结

-   **jemalloc 是什么？** 一个优化过的、高性能的内存管家。  
    
-   **有什么用？** 让你的 C++ 程序**运行更快**（减少锁竞争），**占用内存更整齐**（减少碎片）。  
    
-   **谁在用？** Redis、MySQL (MariaDB)、Android、Firefox 等大名鼎鼎的项目都在用它。  
    

如果你觉得你的程序运行时间长了就变卡，或者多线程性能上不去，换上 jemalloc 往往会有奇效！]]></description>
      <category>C++</category>
      <category>开发工具</category>
      <author>Admin</author>
      <pubDate>Thu, 09 Apr 2026 06:20:32 GMT</pubDate>
    </item>

    <item>
      <title><![CDATA[cpp thread 创建]]></title>
      <link>https://daichangyu.com/zh/blog/cpp-thread-chuang-jian-zhihu-1911824575114745835</link>
      <guid isPermaLink="true">https://daichangyu.com/zh/blog/cpp-thread-chuang-jian-zhihu-1911824575114745835</guid>
      <description><![CDATA[这段 C++ 代码演示了如何使用 `std::thread` 创建并管理线程。以下是逐行解释：

### 代码分析

```cpp
std::thread t([](){  // 1. 创建一个新线程
    std::cout << "Hello from thread!" << std::endl;  // 2. 线程执行的代码
});  // 3. 线程开始执行

t.join();  // 4. 等待线程结束

```

### 详细说明

1.  ​**创建线程对象**​  
    `std::thread t(...)`：  
    

-   声明一个名为 `t` 的线程对象。
-   构造函数参数是一个 ​**lambda 表达式**​ `[](){ ... }`，它定义了线程要执行的任务。
-   当对象 `t` 被创建时，线程立即开始执行。
-   ​**线程任务（Lambda 表达式）​**​

`cpp [](){ std::cout << "Hello from thread!" << std::endl; }`  

-   `[]`：空捕获列表（不捕获外部变量）。
-   `()`：无参数。
-   函数体：向标准输出打印 `"Hello from thread!"` 并换行（`std::endl` 会刷新缓冲区）。
-   ​**线程启动**​  
    线程在 `t` 对象构造完成后**立即开始执行**​ lambda 中的代码，与主线程并发运行。

1.  ​**等待线程结束（`.join()`）​**​  
    `t.join()`：  
    

-   阻塞主线程，直到线程 `t` 完成其任务。
-   确保线程安全退出，避免资源泄漏（必须调用 `join()` 或 `detach()`）。

### 执行流程

```text
sequenceDiagram
    participant 主线程
    participant 子线程

    主线程->>子线程: 创建线程 t (lambda 开始执行)
    子线程->>控制台: 打印 "Hello from thread!"
    主线程->>子线程: t.join() 等待
    子线程-->>主线程: 执行完毕
    主线程->>主线程: 继续执行后续代码

```

控制台子线程主线程控制台子线程主线程创建线程 t (lambda 开始执行)打印 "Hello from thread!"t.join() 等待执行完毕继续执行后续代码

### 关键点

-   ​**并发性**​：子线程与主线程同时运行（打印操作可能发生在 `t.join()` 之前/期间）。
-   ​**资源管理**​：必须调用 `join()`（等待线程结束）或 `detach()`（分离线程），否则程序终止时 `std::terminate` 会被调用。
-   ​**输出顺序不确定性**​：若主线程有其他输出，由于线程调度，打印顺序可能不同（此例中主线程无其他操作）。

### 等价函数写法

若用普通函数替代 lambda：

```cpp
void threadFunc() {
    std::cout << "Hello from thread!" << std::endl;
}

int main() {
    std::thread t(threadFunc); // 传递函数指针
    t.join();
}

```

### 常见错误

-   ​**忘记 join/detach**​：导致程序崩溃。
-   ​**访问共享数据不同步**​：此例无共享数据，安全。

> ​**总结**​：这段代码创建了一个打印消息的线程，并确保主线程等待其完成后再退出，是多线程编程的基础操作。]]></description>
      <category>C++</category>
      <author>Admin</author>
      <pubDate>Fri, 30 May 2025 08:42:32 GMT</pubDate>
    </item>

    <item>
      <title><![CDATA[C++中this到底指针是啥？有啥用？]]></title>
      <link>https://daichangyu.com/zh/blog/c-zhongthisdao-di-zhi-zhen-shi-sha-you-sha-yong-zhihu-1911823698756863109</link>
      <guid isPermaLink="true">https://daichangyu.com/zh/blog/c-zhongthisdao-di-zhi-zhen-shi-sha-you-sha-yong-zhihu-1911823698756863109</guid>
      <description><![CDATA[this 指针是C++类中每个**非静态成员函数**都隐式拥有的一个指针，指向**当前对象**自身。 它的类型是 `ClassName* const`，即“指向当前类类型的常量指针”。

## 常用场景

### 1\. 区分成员变量和参数

当成员变量和函数参数同名时，常用 this-> 区分：

```cpp
class Person {
    std::string name;
public:
    void setName(const std::string& name) {
        this->name = name; // this->name 是成员变量，name 是参数
    }

};

```

**吐槽：一般来说我们都会在函数参数前加上p**

### 2\. 在成员函数中返回当前对象

常用于链式调用（返回 this）

```cpp
class Counter {
    int value;
public:
    Counter& increment() {
        ++value;
        return *this; // 返回当前对象的引用
    }
};

Counter c;
c.increment().increment(); // 支持链式调用

```

### 3\. 作为成员函数指针调用的对象

```cpp
std::bind(&ClassName::func, this, arg1, arg2)

```

这里 this 保证了成员函数 func 是在当前对象上调用的。

### 4\. 在构造函数或成员函数中传递当前对象

```cpp
class Widget {
public:
    void registerSelf() {
        SomeManager::registerWidget(this); // 传递当前对象指针
    }
};

```

### 5\. 防止自赋值

在重载赋值运算符时，常用 this 判断自赋值：

```cpp
MyClass& operator=(const MyClass& other) {
    if (this == &other) return *this; // 检查是否自赋值
    // ...赋值逻辑...
    return *this;
}

```

### 6\. 智能指针获取自身

有时需要获取当前对象的 shared\_ptr，可以用 shared\_from\_this()，但前提是继承自 std::enable\_shared\_from\_this，本质上也是用 this。]]></description>
      <category>C++</category>
      <author>Admin</author>
      <pubDate>Fri, 30 May 2025 08:41:26 GMT</pubDate>
    </item>

    <item>
      <title><![CDATA[回调函数到底是个啥]]></title>
      <link>https://daichangyu.com/zh/blog/hui-tiao-han-shu-dao-di-shi-ge-sha-zhihu-1911808663322067004</link>
      <guid isPermaLink="true">https://daichangyu.com/zh/blog/hui-tiao-han-shu-dao-di-shi-ge-sha-zhihu-1911808663322067004</guid>
      <description><![CDATA[## 回调函数

### 什么是回调函数？

回调函数（Callback Function）就是你把一个**函数“传递”给另一个函数**，**当某个事件发生时**，这个函数会被“回调”执行。 举例：

```cpp
void onDataReceived(int data) {
    // 处理收到的数据
}

void asyncRead(void(*callback)(int)) {
    // ... 异步读取数据
    // 数据到来时
    callback(data); // 调用回调函数
}

```

**回调的最大作用：解耦和灵活**

**直接调用A的缺点**

-   如果B里直接写死调用A，那么B只能做一种固定的事情，扩展性很差。
-   如果以后想让B调用别的函数（比如A1、A2、A3），就得改B的代码，维护成本高。 **用回调的好处**
-   B不关心A具体做什么，只负责“在合适的时候调用你给我的函数”。
-   你可以把不同的函数传给B，B就能做不同的事情，B的代码不用改。
-   这样B就变成了一个“通用工具”，而A是“定制化逻辑”。

### 现实类比

-   你去饭店点菜（B），你告诉厨师（B）你要什么菜（A），厨师只管做你点的菜。
-   如果你每次都要厨师做同一道菜，那厨师的工作就很死板。
-   如果你可以告诉厨师不同的菜名，厨师就能灵活应对不同需求。

### 代码场景举例

没有回调（写死逻辑）

```cpp
void B() {

    // 只能做A的事情

    A();

}

```

**有回调（灵活扩展）**

```cpp
void B(void(*callback)()) {

    // 只负责在合适的时候调用callback

    callback();

}

void A1() { /* ... */ }

void A2() { /* ... */ }

int main() {

    B(A1); // 让B做A1的事

    B(A2); // 让B做A2的事

}

```

-   这样B就能适应不同的需求，A1、A2可以随时换，B不用改。

### 典型应用场景

-   排序时的比较函数（你可以自定义升序、降序、按长度等）  
    
-   遍历容器时的处理逻辑（你可以自定义每个元素怎么处理）  
    
-   异步IO、事件驱动（你可以自定义事件发生时的处理方式）  
    

* * *

### 总结

-   回调让B变成“通用工具”，A变成“定制逻辑”，两者解耦，代码更灵活、可扩展、可复用。  
    
-   如果B里写死A，扩展性和灵活性就没了。  
    

### 复杂的回调设计模式

### 策略模式

概念：

-   策略模式就是把一组算法（或行为）封装成独立的“策略类”，在运行时可以互相替换。
-   这样，使用者（Context）不用关心具体用哪种算法，只需要“注入”一个策略对象即可。

**和回调的关系**

-   策略模式本质上就是“把行为（函数/对象）交给别人”，别人（Context）在合适的时候调用，这就是一种回调思想。

```cpp
// 策略接口

class SortStrategy {

public:

    virtual void sort(std::vector<int>& data) = 0;

    virtual ~SortStrategy() = default;

};

// 具体策略A

class BubbleSort : public SortStrategy {

public:

    void sort(std::vector<int>& data) override {

        // 冒泡排序实现

    }

};

// 具体策略B

class QuickSort : public SortStrategy {

public:

    void sort(std::vector<int>& data) override {

        // 快速排序实现

    }

};

// 上下文

class Context {

    SortStrategy* strategy;

public:

    Context(SortStrategy* s) : strategy(s) {}

    void setStrategy(SortStrategy* s) { strategy = s; }

    void doSort(std::vector<int>& data) { strategy->sort(data); }

};

int main() {

    std::vector<int> data = {3, 1, 4, 2};

    BubbleSort bubble;

    QuickSort quick;

    Context ctx(&bubble);

    ctx.doSort(data); // 用冒泡

    ctx.setStrategy(&quick);

    ctx.doSort(data); // 换成快速

}

```

-   这里Context并不关心用什么排序算法，具体算法由外部注入，这就是“回调思想”的面向对象实现。

### 观察者模式

概念：

-   观察者模式是一种“发布-订阅”机制。
-   一个主题（Subject）可以有多个观察者（Observer），当主题状态变化时，会自动通知所有观察者。

**和回调的关系**

-   观察者注册自己的“回调函数”到主题，主题在事件发生时自动调用这些回调。

**现实举例** 公众号订阅，通知所有人

**代码举例**

```cpp
#include <vector>

#include <iostream>

// Observer 观察者接口
class Observer {

public:
 // 所有 观察这都要实现update方法
    virtual void update(int value) = 0;

};

class Subject {
 // 存储所有的观察者
    std::vector<Observer*> observers;

    int state = 0;

public:

    void attach(Observer* obs) { observers.push_back(obs); }

    void setState(int value) {

        state = value;

        for (auto obs : observers) {
   // 每个观察者都调用自己的update方法，更加灵活
            obs->update(state); // 通知所有观察者

        }

    }

};

class ConcreteObserver : public Observer {

public:

    void update(int value) override {

        std::cout << "收到通知，状态变为: " << value << std::endl;

    }

};

int main() {

    Subject subject;

    ConcreteObserver obs1, obs2;

    subject.attach(&obs1);

    subject.attach(&obs2);

    subject.setState(42); // 所有观察者都会收到通知

}

```]]></description>
      <category>C++</category>
      <category>编程概念</category>
      <author>Admin</author>
      <pubDate>Fri, 30 May 2025 07:51:25 GMT</pubDate>
    </item>

    <item>
      <title><![CDATA[MySQL Connector C 6.1 mingw32编译问题(e=5 拒绝访问)]]></title>
      <link>https://daichangyu.com/zh/blog/mysql-connector-c-6-1-mingw32bian-yi-wen-ti-e-5-ju-jue-fang-zhihu-24646950494</link>
      <guid isPermaLink="true">https://daichangyu.com/zh/blog/mysql-connector-c-6-1-mingw32bian-yi-wen-ti-e-5-ju-jue-fang-zhihu-24646950494</guid>
      <description><![CDATA[今天在编译MySQL Connector C 6.1时候遇到一个问题

![显示拒绝访问](/images/zhihu/mysql-connector-c-6-1-mingw32bian-yi-wen-ti-e-5-ju-jue-fang-zhihu-24646950494/2de73570f54a.jpg)

产生错误的原因是因为安装了MSYS后，利用Make命令会首先执行MSYS中的SHELL命令，从而会导致编译错误，对于这种情况，可以修改 $(WX)/build/msw目录中的makefile.gcc文件，使其默认采用CMD命令行。

makefile.mingw修改前： SHELL := $(COMSPEC)

makefile.mingw修改后： SHELL := C:\\WINDOWS\\system32\\CMD.exe (该路径为实际的CMD.exe的路径)]]></description>
      <category>开发工具</category>
      <author>Admin</author>
      <pubDate>Tue, 18 Feb 2025 14:24:16 GMT</pubDate>
    </item>

    <item>
      <title><![CDATA[tcpdump 抓包命令]]></title>
      <link>https://daichangyu.com/zh/blog/tcpdump-zhua-bao-ming-ling-zhihu-19702568727</link>
      <guid isPermaLink="true">https://daichangyu.com/zh/blog/tcpdump-zhua-bao-ming-ling-zhihu-19702568727</guid>
      <description><![CDATA[`tcpdump`  
举例：  
`tcpdump -i any tcp port 8000 -s 0 -w port.pcap`  
`tcpdump`是一个用于捕获网络数据包的工具。该命令的含义如下：  
`-i any`：在所有网络接口上捕获数据包，any是tcpdump的一个特殊设备，表示所有接口。  
`tcp port 8000`：过滤出所有目标或源端口为8000的TCP数据包。  
`-s 0`：-s参数后跟的数字代表捕获数据包的大小，0代表捕获整个数据包。  
`-w port.pcap`：将捕获的数据包写入名为port.pcap的文件中，以便进一步分析。]]></description>
      <category>网络编程</category>
      <category>Linux</category>
      <author>Admin</author>
      <pubDate>Tue, 21 Jan 2025 12:32:13 GMT</pubDate>
    </item>

    <item>
      <title><![CDATA[什么是协程？]]></title>
      <link>https://daichangyu.com/zh/blog/shen-me-shi-xie-cheng-zhihu-18724411587</link>
      <guid isPermaLink="true">https://daichangyu.com/zh/blog/shen-me-shi-xie-cheng-zhihu-18724411587</guid>
      <description><![CDATA[协程：通过一个线程实现代码块相互切换执行

定义：

协程（英语：coroutine）是计算机程序的一类组件，推广了[协作式多任务](https://zhida.zhihu.com/search?content_id=183767094&content_type=Article&match_order=1&q=%E5%8D%8F%E4%BD%9C%E5%BC%8F%E5%A4%9A%E4%BB%BB%E5%8A%A1&zhida_source=entity)的子程序，允许执行被挂起与被恢复。

举个例子：游戏 《胡闹厨房》

协程式：玩家们不停地协作制作订单

挂起：食物切好，放在锅里煮。订单就被“挂起”

恢复：菜煮好了就恢复

计算机会用异步的方式实现协程

**异步是什么** asynchronous

订单们不是从一开始制作，不停地烹饪，直到一个订单完成，才去制作其他订单，而是中间穿插了多个不同订单的制作

所以异步地执行是指做事情仍按照顺序，但是并不要求顺序在时间上相连，只要按照逻辑的顺序即可。

**协程就是可以suspend和resume的函数，可以暂停这个函数的执行，做其他事情，在成熟时候回来继续执行**

**切分点一般是await（）** 通过coroutine将一个函数切片]]></description>
      <category>编程概念</category>
      <author>Admin</author>
      <pubDate>Thu, 16 Jan 2025 12:52:38 GMT</pubDate>
    </item>

    <item>
      <title><![CDATA[using namespace std 和 using namespace chrono 为什么会有先后顺序？]]></title>
      <link>https://daichangyu.com/zh/blog/using-namespace-std-he-using-namespace-chrono-wei-shen-me-hu-zhihu-18723343856</link>
      <guid isPermaLink="true">https://daichangyu.com/zh/blog/using-namespace-std-he-using-namespace-chrono-wei-shen-me-hu-zhihu-18723343856</guid>
      <description><![CDATA[今天发现使用`using namespace chrono; using namespace std;`是有先后顺序的。顺序不对编译器会报错

```cpp
#include <iostream>
#include <chrono>
using namespace chrono;
using namespace std;

int main() {
    milliseconds ms(1000);  // 编译错误：不明确的符号
    cout << ms.count() << " milliseconds" << endl;
    return 0;
} 

```

在这种情况下，`using namespace std` 会将 `std::milliseconds` 引入作用域，而编译器可能会遇到歧义，因为它无法确定应使用 `std::chrono::milliseconds` 还是 `std::milliseconds`]]></description>
      <category>C++</category>
      <category>开发工具</category>
      <author>Admin</author>
      <pubDate>Thu, 16 Jan 2025 12:49:35 GMT</pubDate>
    </item>

    <item>
      <title><![CDATA[tcp::no_delay 套接字选项]]></title>
      <link>https://daichangyu.com/zh/blog/tcp-no-delay-tao-jie-zi-xuan-xiang-zhihu-18508643166</link>
      <guid isPermaLink="true">https://daichangyu.com/zh/blog/tcp-no-delay-tao-jie-zi-xuan-xiang-zhihu-18508643166</guid>
      <description><![CDATA[最近发现编写的程序在发送时，时间间隔特别小的时候，抓包会发现粘包，组包发送没问题。

![](/images/zhihu/tcp-no-delay-tao-jie-zi-xuan-xiang-zhihu-18508643166/1695363337a0.jpg)

排查之后发现，tcp发送数据会默认延迟。原因是tcp默认会遵循**Nagle 算法**

### **Nagle 算法**

Nagle 算法是一种通过减少小数据包的发送来优化网络效率的机制。它的主要作用是：

1.  **减少小数据包**：合并多个小数据块后再发送，减少网络上的数据包数量。
2.  **降低网络开销**：适用于对吞吐量要求较高的应用。

但是，Nagle 算法会导致一定的延迟，特别是当应用频繁发送小数据包时，这种延迟可能对实时性要求高的场景（如在线游戏、金融交易或远程控制）造成负面影响。

**tcp::no\_delay 的作用**

-   启用 tcp::no\_delay(true)：
-   禁用 Nagle 算法，数据包会立即发送，不会等待积累或合并
-   适用于需要低延迟的场景

**tcp::no\_delay(false)（默认值）**：

-   启用 Nagle 算法，会尝试合并小数据包以提高传输效率，适用于吞吐量优先的场景。

解决：创建完套接字后设置set\_option

```cpp
 m_Socket.set_option(boost::asio::ip::tcp::no_delay(true));

```]]></description>
      <category>C++</category>
      <category>网络编程</category>
      <author>Admin</author>
      <pubDate>Wed, 15 Jan 2025 14:25:12 GMT</pubDate>
    </item>

    <item>
      <title><![CDATA[Vscode 之settings.json（C++篇）]]></title>
      <link>https://daichangyu.com/zh/blog/vscode-zhisettings-json-c-pian-zhihu-18506421665</link>
      <guid isPermaLink="true">https://daichangyu.com/zh/blog/vscode-zhisettings-json-c-pian-zhihu-18506421665</guid>
      <description><![CDATA[`settings.json` 实际上就是vscode的设置。但是有时候会发现多个`settings.json`，这是因为：

-   **项目级别**：在 `.vscode/settings.json`(项目相对路径) 中配置与项目相关的设置，例如特定的编译器路径、语言支持插件配置等。
-   **远程全局级别**：在 `/home/xxx(username)/.vscode-server/data/Machine/settings.json` 中配置通用的远程开发环境设置，例如默认终端路径、远程文件编码等。

个人settings.json设置（全局级别）

```json
{
// 个人比较喜欢用clangd 
"clangd.path": "/home/dcy/.vscode-server/data/User/globalStorage/llvm-vs-code-extensions.vscode-clangd/install/19.1.2/clangd_19.1.2/bin/clangd",
// 用了clangd所以把cpp的给禁用了
"C_Cpp.intelliSenseEngine": "disabled",
// 高亮显示代码块范围（个人强力推荐）
"editor.bracketPairColorization.enabled": true,
"editor.guides.bracketPairs":"active",
// 设置字体：优先级从高到底 如果没有匹配则会往下一级识别
"editor.fontFamily": "'JetBrains Mono', '微软雅黑', Consolas, 'Courier New', monospace",
"editor.fontSize": 16,
// 是否连写
"editor.fontLigatures": false,
 // 字母之间的空隙
"editor.letterSpacing": 0.4,
// 平滑滚动
"editor.smoothScrolling": true,
"editor.fontWeight": "normal",
"files.autoSave": "onWindowChange",
}

```]]></description>
      <category>C++</category>
      <category>开发工具</category>
      <author>Admin</author>
      <pubDate>Wed, 15 Jan 2025 14:15:55 GMT</pubDate>
    </item>

    <item>
      <title><![CDATA[为什么有时SIGPIPE信号既要忽略又要阻塞？]]></title>
      <link>https://daichangyu.com/zh/blog/wei-shen-me-you-shisigpipexin-hao-ji-yao-hu-l-e-you-yao-zu-s-zhihu-739033140</link>
      <guid isPermaLink="true">https://daichangyu.com/zh/blog/wei-shen-me-you-shisigpipexin-hao-ji-yao-hu-l-e-you-yao-zu-s-zhihu-739033140</guid>
      <description><![CDATA[1\. **忽略 SIGPIPE 信号 (signal(SIGPIPE, SIG\_IGN))**

-   **作用**：signal(SIGPIPE, SIG\_IGN) 告诉系统全局忽略 SIGPIPE 信号。当程序向已关闭的管道或套接字写数据时，操作系统不会再发送 SIGPIPE 信号，进程不会因此中断或终止。
-   **作用范围**：这是一个全局设置，适用于整个进程。如果程序中有多个线程，所有线程在发生 SIGPIPE 时都会遵循这个设定，不再响应这个信号。

### 2\. **阻塞 SIGPIPE 信号 (pthread\_sigmask(SIG\_BLOCK, &signal\_mask, nullptr))**

-   **作用**：pthread\_sigmask(SIG\_BLOCK, &signal\_mask, nullptr) 用于在**特定线程中阻塞** SIGPIPE 信号。这意味着，即使信号没有被忽略，特定线程在执行某些操作时可以通过阻塞信号来控制它的传递行为。
-   **作用范围**：这是一个**线程级别**的设置，阻塞信号只影响当前线程，不影响其他线程。

### 3\. **为何既忽略又阻塞？**

在这段代码中，既全局忽略 SIGPIPE 信号，又在某些线程中阻塞 SIGPIPE 信号的做法，通常是为了处理多线程程序中不同线程对信号的不同需求。这种组合使用在以下几个场景中可能非常有用：

1\. **多线程程序中的不同处理需求**

-   **全局忽略**：通常用于确保程序的所有线程在与外部网络、管道或进程通信时，不会因为 SIGPIPE 信号导致进程意外中断。通过全局忽略，系统调用（如 write()）在发生 SIGPIPE 时会返回错误，而不会终止整个进程。
-   **局部阻塞**：某些线程可能有特殊需求。在执行某些关键操作时，比如事务处理、资源分配等，你可能希望**暂时阻塞**信号，以确保在特定代码段中不会有信号打断操作。阻塞信号是一种更为细粒度的控制方式，适合在特定线程或特定代码段中使用。

**举例**：在服务器程序中，网络处理线程通常会忽略 SIGPIPE 信号，但在文件写入或数据库事务操作的线程中，你可能希望**暂时阻塞**该信号，以避免某些特殊情况下信号干扰这些关键操作。

2\. **防止 race condition（竞态条件）**

-   在某些情况下，简单地忽略信号并不足够。某些关键代码段可能需要在完全屏蔽 SIGPIPE 的情况下执行，防止信号在不合适的时间点打断当前线程的执行逻辑。
-   阻塞信号允许你在关键代码段临时关闭信号的处理，执行完后再解除阻塞，从而避免信号在不合适的时机中断操作流程。

3\. **不同的线程需要不同的信号处理策略**

-   如果程序是多线程的，有些线程可能需要对 SIGPIPE 信号进行更细致的处理。例如，一个线程可能在某些阶段需要暂时阻塞 SIGPIPE 信号，而其他线程则可以全局忽略。
-   阻塞信号的机制允许你对每个线程设置不同的信号处理方式，而不会影响全局设定。

4\. **防止遗留信号干扰新的信号处理**

-   有时，在某些复杂的系统中，信号的忽略行为并不能完全保证某些线程不受影响。阻塞信号可以确保即使在信号忽略的情况下，也能避免遗留的 SIGPIPE 信号对特定线程的干扰。
-   忽略信号并不影响信号的产生，而阻塞信号可以确保信号在被解除阻塞之前不会被处理。

### 4\. **实际案例举例**

假设我们有一个多线程的服务器程序，在处理客户端请求时，可能有多个线程同时在进行不同的操作：

-   **网络处理线程**：这些线程可能会经常与外部客户端通信，因此全局忽略 SIGPIPE 信号是合适的做法，防止因为客户端断开连接而导致服务器进程终止。
-   **文件操作线程**：这些线程可能会处理某些敏感的文件写入或数据库操作。如果在写入期间发生管道断开问题，可能导致数据一致性问题，因此可以在这些线程中临时阻塞 SIGPIPE 信号，确保在执行关键操作时不会被中断。

```cpp
// 全局忽略 SIGPIPE 信号，适用于网络处理线程
signal(SIGPIPE, SIG_IGN);

// 文件处理线程：阻塞 SIGPIPE 信号
sigset_t signal_mask;
sigemptyset(&signal_mask);
sigaddset(&signal_mask, SIGPIPE);

// 阻塞 SIGPIPE 信号
pthread_sigmask(SIG_BLOCK, &signal_mask, nullptr);

// 执行文件写入操作，避免信号干扰
write_to_file();

// 解除对 SIGPIPE 信号的阻塞
pthread_sigmask(SIG_UNBLOCK, &signal_mask, nullptr);

```

### 5\. **总结**

-   **忽略 SIGPIPE 信号**：通过 signal(SIGPIPE, SIG\_IGN)，程序全局忽略 SIGPIPE 信号，防止进程因写入已关闭的管道或套接字而终止。通常用于防止程序因通信中断而崩溃。
-   **阻塞 SIGPIPE 信号**：通过 pthread\_sigmask(SIG\_BLOCK, &signal\_mask, nullptr)，可以在线程级别阻塞 SIGPIPE 信号。这种做法适用于特定线程或代码段中，确保信号不会在关键操作期间中断程序的正常运行。]]></description>
      <category>C++</category>
      <category>网络编程</category>
      <category>Linux</category>
      <author>Admin</author>
      <pubDate>Fri, 27 Sep 2024 13:04:57 GMT</pubDate>
    </item>

    <item>
      <title><![CDATA[Modbus通信协议]]></title>
      <link>https://daichangyu.com/zh/blog/modbustong-xin-xie-yi-zhihu-722175970</link>
      <guid isPermaLink="true">https://daichangyu.com/zh/blog/modbustong-xin-xie-yi-zhihu-722175970</guid>
      <description><![CDATA[## **Modbus**

## **Modbus协议的相关知识**

### **概要**

Modbus 是一主多从的通信协议，最多有247个从设备

1.  单播模式 主请求，从相应
2.  广播模式 主请求，从事务处理而不要求返回应答。所以请求指令必须是Modbus标准功能中的写指令

## **Modbus寄存器**

寄存器可以指具体的物理寄存器，也指一块内存区域

1.  RTU

2\. ASCII

**对于串行链路来说：ASCII || RTU （串行链路：信息的各位数据被逐位按顺序传送的线路）**

3\. TCP

### **ModBus ASCII（不常用）消息帧格式**

每8bit都作为两个ASCII字符发送

起始

地址

功能代码

数据

LRC校验

结束

1字符

2字符

2字符

0~2\*252字符

2字符

2字符  
CR，LF

### **ModBus RTU 消息帧格式**

注意：

1.  区别前后两帧：在RTU模式中，消息的发送和接收以至少3.5个字符时间的停顿间隔为标志，当波特率大于19200bps，为了减轻CPU的负担，时间间隔使用固定值，如1.5个字符时间
2.  确定连续：在一帧报文中，必须以连续的字符流发送整个报文帧，如果两个字符间隔大于1.5个字符时间，则认为报文信息不完整，被丢弃

波特率（串行通信）：每秒传输二进制位的个数

### **地址域**

地址字段即设备的地址

0

1~247

248~255

广播地址

从站地址

保留

### **功能码域**

1字节（1~255）

正常情况下返回的响应消息帧设置同样功能码，异常情况下最高位（MSB）置1

### **数据域**

存放功能码需要操作的具体数据

### **字节序和大小端**

大端（Big-Endian）：数据的低位保存在高地址

小端（Small-Endian）：数据的低位保存在低地址

### **Modbus TCP/IP 消息帧格式**

ADU > PDU

PDU = Function code + Data

ADU = PDU + Additional address + Error check

\\= Additional address + Function code + Data + Error check

聚焦Modbus TCP：定义MBAP（Modbus Application Header）

Modbus TCP/IP ADU = MBAP Header + PDU

\\=MBAP Header + Function code + Data

Modbus TCP/IP 协议的最大帧数据长度为260个字节，0~6字节构成MBAP报头

### **Modbus TCP协议格式**

对于Modbus TCP，帧结构略有不同：

1.  **帧结构** : 每个Modbus TCP帧由以下部分组成：

-   **事务标识符** : 2字节，用于事务的唯一标识。
-   **协议标识符** : 2字节，通常为0，表示Modbus协议。
-   **长度字段** : 2字节，表示后续字节的长度（包括功能码和数据字段）。  
    

-   在Modbus协议及许多其他通信协议中，长度信息通常使用两个字节（16位）表示，这是因为  
    

1.  标识范围  
    

-   使用两个字节可以表示的长度范围是 0 到 65535（2^16 - 1）。这使得协议能够支持更大的数据量。
-   如果只使用一个字节（8位），最大长度只能表示到 255（2^8 - 1），这在某些应用中可能不够用。

  

1.  兼容性与标准化  
    

-   使用高位和低位分开表示长度信息是一种标准做法，符合许多网络协议的设计原则。这种设计使得协议在处理多字节数据时保持一致性。
-   在计算机内存中，数据通常以字节为单位存储，多个字节的数据（如16位、32位等）需要分开处理。

  

1.  便于网络传输  
    

-   在网络传输中，数据通常以字节流的形式发送。将长度信息分为高位和低位可以方便地在不同的系统之间进行传输。
-   一些系统可能采用大端字节序（Big Endian），而另一些可能采用小端字节序（Little Endian）。将长度信息分为两个字节可以适应不同的字节序。

  

1.  提高容错率  
    

-   将长度信息分为高八位和低八位是为了表示更大的数据范围，符合协议标准化，便利网络传输，并提高数据的容错性。这种设计在许多通信协议中是常见的做法。

  

  

  

-   **功能码** : 1字节，指定要执行的操作。  
    

-   在Modbus协议中，**异常响应**的功能码是通过将请求的功能码按位或（OR）运算与 0x80（即10000000）结合而成的

  

```cpp
pBuf[7] = pFun | 0x80;        // 将功能码 pFun 的高位设置为1，以指示这是一个异常响应

```

-   **数据字段** : 可变长度，包含与功能码相关的数据

1.  **帧示例**

```text
+----------+----------+----------+----------+----------+
| 事务标识 | 协议标识 | 长度     | 功能码   | 数据字段 |
+----------+----------+----------+----------+----------+

```

对于C++代码来说，用来检查可以先定义一个header

```cpp
    U8View header = ToU8View(co_await pSock->Recv(6, sc_ModbusTimeoutMs));

```

1.  **检查协议标识：**

```cpp
if (header[2] != 0 || header[3] != 0) {
        Warn(fmt::format("{}Wrong protocol idenifier.", pConn));
        co_return false;
    }

```

1.  **检查长度标识**

```cpp
 if (header[4] != 0 || header[5] < 6) {
        Warn(fmt::format("{}Wrong length idenifier.", pConn));
        co_return false;
    }

```

## **Modbus 功能码详解**

### **概要**

取值范围：1~127

**异常时：功能码+0x80（十进制128）**

1.  公共功能码
2.  用户自定义功能码  
    65~72和100~110
3.  保留功能码

### **01（0x01）读取线圈/离散量输出状态**

### **功能**

读取从设备的线圈或离散量的输出状态（DO, Discrete Output离散输出）ON/OFF的状态

### **02 (0x02) 读取离散量输入值**

### **功能**

读取离散量输入，即DI（Discrete Input）的ON/OFF状态]]></description>
      <category>C++</category>
      <category>网络编程</category>
      <author>Admin</author>
      <pubDate>Wed, 25 Sep 2024 14:36:47 GMT</pubDate>
    </item>
  </channel>
</rss>