<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>排查 on 方糖猫Blog</title>
    <link>https://ftmao.com/blog/tags/%E6%8E%92%E6%9F%A5/</link>
    <description>AI 视频、AI Agent 与工程实践笔记</description>
    <generator>Hugo</generator>
    <language>zh-CN</language>
    <lastBuildDate>Wed, 12 Feb 2025 10:00:00 +0800</lastBuildDate><atom:link href="https://ftmao.com/blog/tags/%E6%8E%92%E6%9F%A5/index.xml" rel="self" type="application/rss+xml" /><item>
      <title>☸️ Kubernetes 学习总结与避坑指南</title>
      <link>https://ftmao.com/blog/bookstore/kubernetes-authoritative-guide-notes/</link>
      <pubDate>Wed, 12 Feb 2025 10:00:00 +0800</pubDate>
      <guid>https://ftmao.com/blog/bookstore/kubernetes-authoritative-guide-notes/</guid>
      <description>&lt;h1 id=&#34;-kubernetes-学习总结与避坑指南&#34;&gt;☸️ Kubernetes 学习总结与避坑指南&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;参考书籍：龚正 等《Kubernetes 权威指南：从 Docker 到 Kubernetes 实践全接触》、Marko Lukša《Kubernetes in Action》
目标读者：会一点 Docker、刚接触 K8s，或者「YAML 会抄但一出问题就懵」的同学。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Kubernetes（简称 K8s，因为 K 和 s 之间有 8 个字母）是 Google 开源的容器编排系统，解决了「成百上千个容器跑在成百上千台机器上，谁来调度、谁来扩容、挂了谁来拉起」的问题。它不是一门「背完概念就会」的技术——新人最常见的状态是：每个名词都听过，但它们之间怎么串起来的说不清楚，Pod 一挂就不知道该看哪里。&lt;/p&gt;
&lt;p&gt;这篇文章帮你建立&lt;strong&gt;主干知识框架&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;K8s 集群整体长什么样？Master 和 Node 各自干什么？&lt;/li&gt;
&lt;li&gt;Pod、Node、Service、Ingress、ConfigMap 这些核心对象到底是什么关系？&lt;/li&gt;
&lt;li&gt;Istio 服务网格在解决什么问题？&lt;/li&gt;
&lt;li&gt;共享存储（PV/PVC/NAS）怎么用，有哪些坑？&lt;/li&gt;
&lt;li&gt;排查 K8s 问题需要补哪些 Unix 网络编程基础知识？&lt;/li&gt;
&lt;li&gt;生产环境如何做内外网访问隔离（私网端点 / 内网 LB / NetworkPolicy）？&lt;/li&gt;
&lt;li&gt;在阿里云 ACK（以及 AWS EKS）上落地时要注意什么？&lt;/li&gt;
&lt;li&gt;Jenkins 如何与 K8s 打通，实现自动化部署、验证与失败回滚？&lt;/li&gt;
&lt;li&gt;遇到 CrashLoopBackOff、OOMKilled、502、DNS 慢这些经典问题，该按什么思路排查？&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一k8s-整体架构一个中心化大脑--一群干活的节点&#34;&gt;一、K8s 整体架构：一个「中心化大脑 + 一群干活的节点」&lt;/h2&gt;
&lt;p&gt;K8s 集群在逻辑上分为两大部分：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;控制平面（Control Plane，俗称 Master）&lt;/strong&gt;：集群的大脑，负责「决策」——调度、扩缩容、故障自愈。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;工作节点（Node）&lt;/strong&gt;：真正跑容器的机器，负责「执行」。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;graph TB
    subgraph 控制平面[&amp;#34;控制平面 Control Plane（阿里云 ACK 托管，用户不可见）&amp;#34;]
        APIServer[kube-apiserver&amp;lt;br/&amp;gt;集群唯一入口，所有操作都经过它]
        ETCD[(etcd&amp;lt;br/&amp;gt;分布式 KV 存储&amp;lt;br/&amp;gt;集群所有状态都在这里)]
        Scheduler[kube-scheduler&amp;lt;br/&amp;gt;决定 Pod 调度到哪个 Node]
        CM[kube-controller-manager&amp;lt;br/&amp;gt;各种控制器：副本数维持、节点监控等]
        CCM[cloud-controller-manager&amp;lt;br/&amp;gt;对接云厂商：SLB/EBS/路由]
    end

    subgraph 节点1[&amp;#34;Worker Node 1&amp;#34;]
        K1[kubelet&amp;lt;br/&amp;gt;节点上的「包工头」]
        P1[kube-proxy&amp;lt;br/&amp;gt;维护 Service 网络规则]
        C1[容器运行时&amp;lt;br/&amp;gt;containerd]
        Pod1[Pod A] ~~~ Pod2[Pod B]
    end

    subgraph 节点2[&amp;#34;Worker Node 2&amp;#34;]
        K2[kubelet]
        P2[kube-proxy]
        C2[containerd]
        Pod3[Pod C]
    end

    APIServer --&amp;gt; ETCD
    Scheduler --&amp;gt; APIServer
    CM --&amp;gt; APIServer
    CCM --&amp;gt; APIServer
    K1 --&amp;gt; APIServer
    K2 --&amp;gt; APIServer
    User[kubectl / CI/CD] --&amp;gt; APIServer&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;记住这条主线：&lt;strong&gt;所有组件只跟 apiserver 说话，apiserver 把状态写进 etcd&lt;/strong&gt;。你敲的每一条 &lt;code&gt;kubectl&lt;/code&gt; 命令、每一个控制器的决策，都是「读/写 apiserver」这个动作。理解了这一点，后面所有概念都好串了。&lt;/p&gt;
&lt;p&gt;K8s 的核心设计思想是&lt;strong&gt;声明式 API + 控制器循环&lt;/strong&gt;：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;graph LR
    A[你提交 YAML&amp;lt;br/&amp;gt;期望状态：3 个副本] --&amp;gt; B[apiserver 存进 etcd]
    B --&amp;gt; C{控制器不断对比&amp;lt;br/&amp;gt;期望状态 vs 实际状态}
    C --&amp;gt;|实际只有 2 个| D[再创建 1 个 Pod]
    D --&amp;gt; C
    C --&amp;gt;|一致| E[什么都不做]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;这就是「自愈」的本质：不是有人盯着修，而是控制器永远在循环纠偏。所以 K8s 里的对象是「期望状态」的描述，不是一条条命令。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二node干活的机器&#34;&gt;二、Node：干活的机器&lt;/h2&gt;
&lt;h3 id=&#34;21-node-上有什么&#34;&gt;2.1 Node 上有什么&lt;/h3&gt;
&lt;p&gt;每个 Node 上必装三个组件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;kubelet&lt;/strong&gt;：节点代理。接收 apiserver 下发的 Pod 定义（PodSpec），调用容器运行时把容器拉起来，并持续上报节点和 Pod 状态。Pod 挂了重启、探针检测，都是 kubelet 干的。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;容器运行时&lt;/strong&gt;：真正拉镜像、跑容器的软件。Docker 已在 K8s 1.24 后被移除，现在主流是 &lt;strong&gt;containerd&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;kube-proxy&lt;/strong&gt;：维护节点上的网络规则（iptables/IPVS），让 Service 的虚拟 IP 能转发到真实 Pod。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;22-节点相关的避坑点&#34;&gt;2.2 节点相关的避坑点&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;节点 NotReady&lt;/strong&gt;：最常见的原因是 kubelet 挂了、节点磁盘满（DiskPressure）、内存不足（MemoryPressure）或网络不通。排查顺序：先 &lt;code&gt;kubectl describe node &amp;lt;名字&amp;gt;&lt;/code&gt; 看 Conditions，再登节点看 &lt;code&gt;systemctl status kubelet&lt;/code&gt; 和日志 &lt;code&gt;journalctl -u kubelet&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;磁盘压力&lt;/strong&gt;：容器日志、镜像、emptyDir 都在吃节点磁盘。务必给应用日志配轮转（logrotate 或运行时自带的日志上限 &lt;code&gt;containerLogMaxSize&lt;/code&gt;），否则磁盘写满会把节点上所有 Pod 驱逐（Evicted）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;不要随意登节点手工改东西&lt;/strong&gt;：K8s 期望节点是「牛」不是「宠物」——可替换、不特殊。手工装的 Agent、改的 iptables 规则，节点一重建全没了。需要节点级能力请用 DaemonSet。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&#34;三podk8s-的最小调度单元&#34;&gt;三、Pod：K8s 的最小调度单元&lt;/h2&gt;
&lt;h3 id=&#34;31-为什么不是直接调度容器&#34;&gt;3.1 为什么不是直接调度容器&lt;/h3&gt;
&lt;p&gt;Pod 是一组&lt;strong&gt;共享网络和存储&lt;/strong&gt;的容器集合。同一个 Pod 里的容器：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;共享同一个 IP 和端口空间（通过 &lt;code&gt;localhost&lt;/code&gt; 直接互通）&lt;/li&gt;
&lt;li&gt;可以共享 Volume&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;graph TB
    subgraph Pod[&amp;#34;Pod（10.0.1.15）&amp;#34;]
        direction LR
        C1[主容器&amp;lt;br/&amp;gt;app:8080]
        C2[边车容器&amp;lt;br/&amp;gt;日志采集]
        V[(共享 Volume&amp;lt;br/&amp;gt;日志目录)]
        C1 --&amp;gt; V
        C2 --&amp;gt; V
    end
    C1 -.-&amp;gt;|localhost:8080| C2&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;这个设计的经典用途就是 &lt;strong&gt;Sidecar（边车）模式&lt;/strong&gt;：日志采集、流量代理（Istio 的 Envoy）都以边车容器形式注入 Pod，主容器无感知。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;新人直觉「一个 Pod 跑一个容器」，这对 90% 的场景是对的。只有容器之间必须同生共死、共享 localhost 或共享文件时，才放进同一个 Pod。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;32-pod-生命周期与探针&#34;&gt;3.2 Pod 生命周期与探针&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;stateDiagram-v2
    [*] --&amp;gt; Pending: 创建，等调度/拉镜像
    Pending --&amp;gt; Running: 调度成功，容器启动
    Running --&amp;gt; Succeeded: 正常退出（Job 类）
    Running --&amp;gt; Failed: 异常退出
    Running --&amp;gt; Running: 探针失败→kubelet 重启容器&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&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;作用&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;livenessProbe&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;判断容器是否活着，失败则&lt;strong&gt;重启容器&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;太灵敏 → 无限重启循环&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;readinessProbe&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;判断是否能接流量，失败则从 Service 摘除&lt;/td&gt;
					&lt;td&gt;不配 → 启动期请求打到没 ready 的 Pod，报 502&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;startupProbe&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;启动探针，成功前禁用另外两个&lt;/td&gt;
					&lt;td&gt;慢启动应用（如老 Java 服务）不配 → 被 liveness 误杀&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;33-资源-requestslimits-与-qos最容易被忽视的重灾区&#34;&gt;3.3 资源 requests/limits 与 QoS：最容易被忽视的重灾区&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;resources&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;requests&lt;/span&gt;:        &lt;span style=&#34;color:#75715e&#34;&gt;# 调度依据：保证分到这么多&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;cpu&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;250m&amp;#34;&lt;/span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# 0.25 核&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;memory&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;512Mi&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;limits&lt;/span&gt;:          &lt;span style=&#34;color:#75715e&#34;&gt;# 使用上限&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;cpu&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;500m&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;memory&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1Gi&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;requests 是调度的唯一依据&lt;/strong&gt;：节点剩余可分配资源 ≥ Pod 的 requests 总和，Pod 才调度得上去。不配 requests，调度就是瞎排，节点超载。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CPU 超 limit → 被限流（throttle），容器变慢但不死；内存超 limit → OOMKilled，直接杀&lt;/strong&gt;。这是两种完全不同的失败模式，排查时先分清。&lt;/li&gt;
&lt;li&gt;QoS 等级：requests=limits 为 &lt;code&gt;Guaranteed&lt;/code&gt;（最后被驱逐）；都不配为 &lt;code&gt;BestEffort&lt;/code&gt;（节点资源紧张时最先被杀）。生产核心服务至少配 &lt;code&gt;Burstable&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;四工作负载不要直接创建裸-pod&#34;&gt;四、工作负载：不要直接创建裸 Pod&lt;/h2&gt;
&lt;p&gt;实际工作中你几乎不会手写 Pod，而是使用「管理 Pod 的控制器」：&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;Deployment&lt;/td&gt;
					&lt;td&gt;无状态服务（Web/API）&lt;/td&gt;
					&lt;td&gt;副本数 + 滚动更新 + 回滚&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;StatefulSet&lt;/td&gt;
					&lt;td&gt;有状态服务（MySQL/Kafka）&lt;/td&gt;
					&lt;td&gt;稳定的名字和网络标识、按序启停&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;DaemonSet&lt;/td&gt;
					&lt;td&gt;节点级 Agent（日志/监控）&lt;/td&gt;
					&lt;td&gt;每个 Node 跑一个&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Job / CronJob&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;p&gt;Deployment 滚动更新过程：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;sequenceDiagram
    participant U as 用户
    participant D as Deployment
    participant RS1 as ReplicaSet v1
    participant RS2 as ReplicaSet v2

    U-&amp;gt;&amp;gt;D: kubectl set image 更新镜像
    D-&amp;gt;&amp;gt;RS2: 创建新 RS，先拉起 1 个新 Pod
    RS2--&amp;gt;&amp;gt;D: 新 Pod ready
    D-&amp;gt;&amp;gt;RS1: 缩掉 1 个旧 Pod
    Note over D,RS2: 循环：新 +1 → 旧 -1
    D-&amp;gt;&amp;gt;RS1: 缩到 0（旧 RS 保留，可回滚）
    U-&amp;gt;&amp;gt;D: kubectl rollout undo（随时回滚）&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;避坑点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;maxSurge / maxUnavailable&lt;/strong&gt; 控制滚动节奏。默认 25%/25%，意味着更新中可能瞬间少 25% 的可用副本——容量紧张的服务要调小 maxUnavailable。&lt;/li&gt;
&lt;li&gt;回滚靠旧 ReplicaSet 保留的 Pod 模板，&lt;code&gt;revisionHistoryLimit&lt;/code&gt; 默认 10，别设成 0 否则无法回滚。&lt;/li&gt;
&lt;li&gt;镜像 tag 不要用 &lt;code&gt;latest&lt;/code&gt;：无法回滚、无法审计，且 &lt;code&gt;imagePullPolicy&lt;/code&gt; 行为反直觉。用 git commit 号或语义化版本。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;五k8s-网络模型与必备的-unix-网络编程知识&#34;&gt;五、K8s 网络模型与必备的 Unix 网络编程知识&lt;/h2&gt;
&lt;p&gt;K8s 的网络问题占了线上故障的一半以上。而很多「K8s 网络问题」本质上是 &lt;strong&gt;Unix 网络编程/TCP 协议问题&lt;/strong&gt;，只是发生在容器环境里。这一节把两边打通。&lt;/p&gt;
&lt;h3 id=&#34;51-k8s-网络的三条铁律&#34;&gt;5.1 K8s 网络的三条铁律&lt;/h3&gt;
&lt;p&gt;K8s 对网络模型只有三个基本要求（具体实现交给 CNI 插件，如 Flannel、Calico、阿里云 Terway）：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;每个 Pod 有自己的独立 IP&lt;/li&gt;
&lt;li&gt;任意两个 Pod 之间可以直接通信（不经过 NAT）&lt;/li&gt;
&lt;li&gt;Node 和 Pod 之间可以直接通信&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;graph LR
    subgraph 节点A[&amp;#34;Node A&amp;#34;]
        PA[&amp;#34;Pod A&amp;lt;br/&amp;gt;10.244.1.5&amp;#34;]
    end
    subgraph 节点B[&amp;#34;Node B&amp;#34;]
        PB[&amp;#34;Pod B&amp;lt;br/&amp;gt;10.244.2.8&amp;#34;]
    end
    PA &amp;lt;--&amp;gt;|&amp;#34;Pod 网络（CNI：Terway/Flannel/Calico）&amp;lt;br/&amp;gt;直连，无 NAT&amp;#34;| PB&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;52-service一组-pod-的稳定入口&#34;&gt;5.2 Service：一组 Pod 的稳定入口&lt;/h3&gt;
&lt;p&gt;Pod 会漂移（重建后 IP 就变了），所以不能在代码里写死 Pod IP。Service 提供&lt;strong&gt;一个固定虚拟 IP（ClusterIP）+ DNS 名字&lt;/strong&gt;，负载均衡到后端 Pod。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;graph LR
    Client[客户端 Pod] --&amp;gt;|&amp;#34;访问 my-svc:80&amp;lt;br/&amp;gt;DNS 解析为 10.96.0.10&amp;#34;| SVC[&amp;#34;Service: my-svc&amp;lt;br/&amp;gt;ClusterIP 10.96.0.10&amp;#34;]
    SVC --&amp;gt;|kube-proxy 的 iptables/IPVS 规则转发| P1[Pod 1]
    SVC --&amp;gt; P2[Pod 2]
    SVC --&amp;gt; P3[Pod 3]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;三种 Service 类型：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ClusterIP&lt;/strong&gt;（默认）：仅集群内可达&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NodePort&lt;/strong&gt;：在每个节点开一个高端口（30000-32767），可从集群外访问&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LoadBalancer&lt;/strong&gt;：对接云厂商负载均衡器（阿里云 CLB/SLB、AWS NLB/ALB），对外暴露的标准姿势&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;53-为什么排查-k8s-网络要懂-unix-网络编程&#34;&gt;5.3 为什么排查 K8s 网络要懂 Unix 网络编程&lt;/h3&gt;
&lt;p&gt;下面这几组知识，是在 K8s 环境里排查连接问题的「元技能」：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;（1）TCP 连接状态与 TIME_WAIT&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;TCP 挥手后主动关闭方会进入 TIME_WAIT 状态，默认保持 2MSL（Linux 上约 60s）。在高并发短连接场景（比如服务间大量 HTTP/1.0 式短调用），客户端端口会被 TIME_WAIT 大量占用，最终 &lt;code&gt;Cannot assign requested address&lt;/code&gt;。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;stateDiagram-v2
    ESTABLISHED --&amp;gt; FIN_WAIT1: 主动方 close()
    FIN_WAIT1 --&amp;gt; FIN_WAIT2: 收到对端 ACK
    FIN_WAIT2 --&amp;gt; TIME_WAIT: 收到对端 FIN
    TIME_WAIT --&amp;gt; CLOSED: 2MSL 超时（约60s）
    ESTABLISHED --&amp;gt; CLOSE_WAIT: 对端先 close()
    CLOSE_WAIT --&amp;gt; LAST_ACK: 我方 close()
    LAST_ACK --&amp;gt; CLOSED&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;K8s 里的对应症状与解法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;症状：服务间调用偶发超时，&lt;code&gt;ss -s&lt;/code&gt; 看到 timewait 几万。&lt;/li&gt;
&lt;li&gt;正解：&lt;strong&gt;应用层用长连接 + 连接池&lt;/strong&gt;（HTTP keep-alive、gRPC），别依赖 &lt;code&gt;net.ipv4.tcp_tw_reuse&lt;/code&gt; 这类内核参数硬扛。&lt;/li&gt;
&lt;li&gt;另一个常见坑是 &lt;strong&gt;CLOSE_WAIT 堆积&lt;/strong&gt;：对端关了连接但你的代码没 close()（连接泄漏），&lt;code&gt;ss -ant | grep CLOSE_WAIT&lt;/code&gt; 一查便知。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;（2）socket、backlog 与「连接被 Reset」&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;服务端 &lt;code&gt;listen(fd, backlog)&lt;/code&gt; 的 backlog 是「已完成三次握手但应用还没 accept」的队列长度。K8s 场景下突发流量打到刚重启的 Pod，如果应用 backlog 太小（或迟迟不 accept），内核会直接 RST，客户端看到的是 &lt;code&gt;Connection reset by peer&lt;/code&gt;。这类问题在 Pod 扩容瞬间、探针刚通过时高发——&lt;strong&gt;readinessProbe 通过 ≠ 应用真的能扛流量&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;（3）epoll 与 I/O 多路复用&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;一个进程通过 &lt;code&gt;epoll&lt;/code&gt; 可以管理数万连接（C10K 问题的解法）。Nginx Ingress、Envoy 都是 epoll 模型。要懂的点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;进程能开的连接数受 &lt;strong&gt;文件描述符上限&lt;/strong&gt;限制：&lt;code&gt;ulimit -n&lt;/code&gt;。容器里同样生效，高并发服务记得确认 limit（&lt;code&gt;cat /proc/&amp;lt;pid&amp;gt;/limits&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;每个 TCP 连接 = 一个四元组（源IP:源端口 → 目标IP:目标端口）。客户端对单一目标的并发连接数理论上受源端口数（约 2.8 万个可用）限制——这又回到「必须用连接池复用连接」。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;（4）conntrack：K8s 特有的网络坑&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;kube-proxy 的 iptables 模式依赖内核 conntrack（连接跟踪表）。节点上连接数巨大时 conntrack 表被打满（默认 &lt;code&gt;nf_conntrack_max&lt;/code&gt; 往往不够），表现为&lt;strong&gt;新建连接随机丢包、无日志&lt;/strong&gt;，极难排查。解法：调大 &lt;code&gt;net.netfilter.nf_conntrack_max&lt;/code&gt;，或干脆把 kube-proxy 切到 IPVS 模式。阿里云 ACK 的 Terway 模式在这方面压力小很多。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;（5）DNS：K8s 里的「隐形依赖」&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;集群内所有服务名解析都靠 CoreDNS。两个经典坑：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;glibc 的 DNS 解析是串行的&lt;/strong&gt;，且默认 &lt;code&gt;ndots:5&lt;/code&gt; 导致集群内短域名先查 5 次后缀。症状：应用偶发解析慢 5s（一次超时重传）。解法：FQDN 写法 &lt;code&gt;my-svc.my-ns.svc.cluster.local.&lt;/code&gt;（结尾加点）或调整 Pod 的 &lt;code&gt;dnsConfig&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;Java 应用默认&lt;strong&gt;永久缓存 DNS 结果&lt;/strong&gt;（&lt;code&gt;networkaddress.cache.ttl=-1&lt;/code&gt;），Service 后端 IP 变了 JVM 不知道。容器里务必显式设置 DNS 缓存 TTL（如 30s）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;54-内外网访问隔离哪些服务能暴露哪些必须藏住&#34;&gt;5.4 内外网访问隔离：哪些服务能暴露，哪些必须藏住&lt;/h3&gt;
&lt;p&gt;生产集群的基本安全原则：&lt;strong&gt;默认所有东西都不出集群，只开必要的口子&lt;/strong&gt;。K8s 默认网络是「全通」的（任何 Pod 可以访问任何 Pod，LoadBalancer 一不小心就开到公网），隔离要靠自己显式配置。隔离分三个层面，从外到内：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;graph TB
    Internet[公网用户] --&amp;gt;|只放行 443| WAF[WAF / 安全组&amp;lt;br/&amp;gt;云平台层]
    WAF --&amp;gt; PubLB[公网 ALB/CLB&amp;lt;br/&amp;gt;仅 Web 入口服务]
    PubLB --&amp;gt; PubIng[Ingress Controller&amp;lt;br/&amp;gt;公网命名空间]
    PubIng --&amp;gt; WebSvc[Web Service&amp;lt;br/&amp;gt;ClusterIP]

    Office[办公网/运维] --&amp;gt;|VPN/跳板机| IntLB[内网 LoadBalancer&amp;lt;br/&amp;gt;intranet 类型]
    IntLB --&amp;gt; AdminSvc[管理后台 / 监控&amp;lt;br/&amp;gt;Grafana / Jenkins]

    subgraph 集群内[&amp;#34;集群内部（东西向流量）&amp;#34;]
        WebSvc --&amp;gt;|NetworkPolicy 允许| AppSvc[业务 Service]
        AppSvc --&amp;gt;|NetworkPolicy 允许| DBSvc[数据库 Proxy Service]
        AppSvc -.-&amp;gt;|NetworkPolicy 拒绝| Other[其他 namespace]
    end&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;第一层：云网络边界（VPC / 安全组）&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;API Server 用私网端点&lt;/strong&gt;：阿里云 ACK 创建集群时选择「专有网络（私网）」API Server 访问，或只绑定内网 EIP，运维通过 VPN/跳板机访问；公网端点即便有证书认证也是攻击面。AWS EKS 对应 endpoint private access。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;节点安全组收紧入方向&lt;/strong&gt;：只放行 NodePort 范围给内网、放行 LB 健康检查来源，其余一律拒绝。ACK 的节点安全组默认规则要审一遍。&lt;/li&gt;
&lt;li&gt;数据库、Redis 这类云产品走 VPC 内网地址，安全组只对集群节点网段开放。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;第二层：Service 暴露方式——内外网分流的关键&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;LoadBalancer 类型 Service 默认创建的是&lt;strong&gt;公网 LB&lt;/strong&gt;，这是最常见的「误暴露」事故。面向内部的服务要用注解显式声明内网 LB：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 阿里云：内网 CLB（VPC 内可达，公网不可达）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;apiVersion&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;v1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;kind&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;metadata&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;internal-admin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;annotations&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;service.beta.kubernetes.io/alibaba-cloud-loadbalancer-address-type&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;intranet&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;spec&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;type&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;LoadBalancer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;ports&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;port&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;80&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;AWS EKS 对应注解：&lt;code&gt;service.beta.kubernetes.io/aws-load-balancer-internal: &amp;quot;true&amp;quot;&lt;/code&gt;（NLB）或 &lt;code&gt;aws-load-balancer-scheme: internal&lt;/code&gt;（ALB Controller）。&lt;/p&gt;
&lt;p&gt;经验法则：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对外服务：公网 ALB/CLB + Ingress，前面最好再挂 WAF。&lt;/li&gt;
&lt;li&gt;对内服务（管理后台、监控、Jenkins）：内网 LB 或纯 ClusterIP，配合 VPN/跳板机访问。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;默认用 ClusterIP&lt;/strong&gt;，需要出集群时再显式升级类型——把「暴露」当成一个需要评审的动作。&lt;/li&gt;
&lt;li&gt;Ingress 上还可以用注解做来源 IP 白名单（如 &lt;code&gt;nginx.ingress.kubernetes.io/whitelist-source-range: 10.0.0.0/8&lt;/code&gt;），给内部接口再加一道闸。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;第三层：NetworkPolicy——集群内部的东西向隔离&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;即使流量不出集群，「测试 namespace 的 Pod 误连生产数据库」这类事故也常见。NetworkPolicy 是 Pod 级的防火墙（需要 CNI 支持，ACK 的 Terway、Calico 都支持，Flannel 不支持）：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 第一步：namespace 默认全拒（白名单模式的起点）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;apiVersion&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;kind&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;NetworkPolicy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;metadata&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;default-deny&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;namespace&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;prod&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;spec&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;podSelector&lt;/span&gt;: {}          &lt;span style=&#34;color:#75715e&#34;&gt;# 选中 namespace 内所有 Pod&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;policyTypes&lt;/span&gt;: [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Ingress&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Egress&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 第二步：只放行需要的流量&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;apiVersion&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;kind&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;NetworkPolicy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;metadata&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;allow-web-to-app&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;namespace&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;prod&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;spec&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;podSelector&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;matchLabels&lt;/span&gt;: {&lt;span style=&#34;color:#f92672&#34;&gt;app&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;order-svc}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;policyTypes&lt;/span&gt;: [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Ingress&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;ingress&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;podSelector&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;matchLabels&lt;/span&gt;: {&lt;span style=&#34;color:#f92672&#34;&gt;app&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;web-frontend}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;ports&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        - &lt;span style=&#34;color:#f92672&#34;&gt;port&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;8080&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;避坑点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;NetworkPolicy 是&lt;strong&gt;白名单累加&lt;/strong&gt;模型：任何一条 policy 选中某 Pod，该 Pod 未被放行的方向就被默认拒绝。写漏了 DNS（Egress 到 kube-dns 的 53 端口）会导致全 namespace 解析失败——默认拒绝后记得显式放行 DNS。&lt;/li&gt;
&lt;li&gt;策略&lt;strong&gt;只对选中后新建立的连接生效&lt;/strong&gt;，且 Flannel 下写了也不生效（静默失效，最坑的一种）。&lt;/li&gt;
&lt;li&gt;云安全组管的是「节点/LB 维度」，NetworkPolicy 管的是「Pod 维度」，两者互补不替代。&lt;/li&gt;
&lt;li&gt;上了 Istio 的话，还可以用 AuthorizationPolicy 做带身份（mTLS 服务身份）的七层鉴权，比纯 IP/端口的 NetworkPolicy 更细。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&#34;六ingresshttp-流量的统一入口&#34;&gt;六、Ingress：HTTP 流量的统一入口&lt;/h2&gt;
&lt;p&gt;Service 解决的是四层（TCP）负载均衡；Ingress 解决的是七层（HTTP/HTTPS）路由：按域名、按路径把外部流量分发到不同 Service。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;graph TB
    User[外部用户] --&amp;gt;|HTTPS| LB[云负载均衡&amp;lt;br/&amp;gt;阿里云 ALB/CLB]
    LB --&amp;gt; IC[Ingress Controller&amp;lt;br/&amp;gt;Nginx / ALB Ingress]
    IC --&amp;gt;|&amp;#34;a.example.com/api/*&amp;#34;| S1[Service: api]
    IC --&amp;gt;|&amp;#34;a.example.com/web/*&amp;#34;| S2[Service: web]
    IC --&amp;gt;|&amp;#34;b.example.com/*&amp;#34;| S3[Service: admin]
    S1 --&amp;gt; P1[api Pod]
    S2 --&amp;gt; P2[web Pod]
    S3 --&amp;gt; P3[admin Pod]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;注意分清两层：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Ingress 资源&lt;/strong&gt;（YAML 对象）：只是路由规则的声明，本身不做任何事。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ingress Controller&lt;/strong&gt;（真正干活的组件）：如 ingress-nginx、阿里云 ALB Ingress Controller。它 watch Ingress 资源，把规则翻译成 Nginx 配置并热加载。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;避坑点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pathType: Prefix&lt;/code&gt; 和 &lt;code&gt;Exact&lt;/code&gt; 的区别，&lt;code&gt;/api&lt;/code&gt; 配 Prefix 会把 &lt;code&gt;/apiserver&lt;/code&gt; 也匹配进去。&lt;/li&gt;
&lt;li&gt;后端重写（&lt;code&gt;rewrite-target&lt;/code&gt;）是最容易写错的注解，先想清楚「客户端路径 → 后端真实路径」的映射。&lt;/li&gt;
&lt;li&gt;HTTPS 证书放在 Secret 里，过期忘续是经典事故——建议上 cert-manager 自动签发续期。&lt;/li&gt;
&lt;li&gt;502 的第一排查动作：看 Ingress Controller 日志里 upstream 是「连接拒绝」（Pod 没 ready）还是「超时」（应用卡死）。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;七configmap-与-secret配置和代码分离&#34;&gt;七、ConfigMap 与 Secret：配置和代码分离&lt;/h2&gt;
&lt;p&gt;十二要素应用的第一条就是「配置存环境」。K8s 里对应两个对象：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ConfigMap&lt;/strong&gt;：普通配置（应用参数、配置文件、特性开关）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Secret&lt;/strong&gt;：敏感配置（密码、密钥、证书），etcd 中 Base64 编码（注意：&lt;strong&gt;Base64 不是加密&lt;/strong&gt;，生产环境要开 etcd 静态加密或对接 KMS）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;两种注入方式：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 方式一：环境变量&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;env&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;DB_HOST&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;valueFrom&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;configMapKeyRef&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;app-config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;key&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;db_host&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 方式二：挂载为文件（推荐，支持热更新）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;volumeMounts&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;mountPath&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/etc/app&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;volumes&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;configMap&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;app-config&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;两个必踩的坑，提前告诉你：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;环境变量注入的配置，改了 ConfigMap 不会生效&lt;/strong&gt;，必须重启 Pod。文件挂载方式会自动更新（kubelet 定期同步，有分钟级延迟），但应用要支持 reload。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;subPath&lt;/code&gt; 挂载的 ConfigMap 不会自动更新&lt;/strong&gt;。这是用了 subPath 挂单个配置文件的同学必踩的坑——改完 ConfigMap 发现容器里还是旧的。解法：挂载整个目录，或接受重启 Pod 的事实。&lt;/li&gt;
&lt;li&gt;ConfigMap 有 1MB 大小限制，别把大文件塞进去。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&#34;八共享存储pv--pvc--storageclass&#34;&gt;八、共享存储：PV / PVC / StorageClass&lt;/h2&gt;
&lt;p&gt;容器是临时的，数据要持久化就必须落到外部存储。K8s 的存储抽象分三层：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;graph TB
    subgraph 管理员/云平台侧
        SC[StorageClass&amp;lt;br/&amp;gt;定义「用什么盘」&amp;lt;br/&amp;gt;如 alicloud-disk-essd / nas]
        PV[PersistentVolume&amp;lt;br/&amp;gt;一块真实的存储&amp;lt;br/&amp;gt;云盘/NAS 文件系统]
    end
    subgraph 应用侧
        PVC[PersistentVolumeClaim&amp;lt;br/&amp;gt;「我要 100Gi 存储」的申请单]
        Pod[Pod 挂载 PVC]
    end
    PVC --&amp;gt;|绑定| PV
    SC --&amp;gt;|动态供给：PVC 一创建&amp;lt;br/&amp;gt;自动开出对应 PV| PV
    Pod --&amp;gt; PVC&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;现代用法几乎全是&lt;strong&gt;动态供给&lt;/strong&gt;：你只需要写 PVC 声明要多少空间，StorageClass 自动调用云厂商 API 创建云盘/NAS，不用手工建 PV。&lt;/p&gt;
&lt;p&gt;三种访问模式（Access Modes）是高频考点：&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;ReadWriteOnce (RWO)&lt;/td&gt;
					&lt;td&gt;只能挂到一个节点&lt;/td&gt;
					&lt;td&gt;云盘（阿里云 ESSD、AWS EBS）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;ReadWriteMany (RWX)&lt;/td&gt;
					&lt;td&gt;多节点共享读写&lt;/td&gt;
					&lt;td&gt;文件存储（阿里云 NAS、AWS EFS）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;ReadOnlyMany (ROX)&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;p&gt;&lt;strong&gt;共享存储的避坑清单：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;云盘（RWO）不能跨可用区挂载&lt;/strong&gt;。PV 创建在可用区 A，Pod 被调度到可用区 B 就永远 Pending。解法：用 &lt;code&gt;WaitForFirstConsumer&lt;/code&gt; 模式的 StorageClass（等 Pod 定好节点再开盘），并用拓扑约束调度。&lt;/li&gt;
&lt;li&gt;要&lt;strong&gt;多副本共享文件&lt;/strong&gt;（如多个 Web Pod 共享上传目录），必须用 NAS/EFS 这类 RWX 存储，云盘做不到。&lt;/li&gt;
&lt;li&gt;NAS 挂载注意&lt;strong&gt;权限问题&lt;/strong&gt;：容器内进程 UID 和 NAS 目录属主不匹配会 Permission denied，用 &lt;code&gt;securityContext.fsGroup&lt;/code&gt; 或挂载参数解决。&lt;/li&gt;
&lt;li&gt;删除 PVC 会不会丢数据，取决于 PV 的 &lt;code&gt;persistentVolumeReclaimPolicy&lt;/code&gt;（Retain 保留 / Delete 连盘一起删）。&lt;strong&gt;生产数据盘务必确认是 Retain&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;StatefulSet 用 &lt;code&gt;volumeClaimTemplates&lt;/code&gt; 给每个副本独立开盘，扩缩容时数据卷跟着 Pod 名字走，这是有状态服务的标准姿势。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&#34;九istio-服务网格把网络能力从业务代码里剥出来&#34;&gt;九、Istio 服务网格：把「网络能力」从业务代码里剥出来&lt;/h2&gt;
&lt;p&gt;微服务多了之后，每个服务都要自己实现超时重试、熔断、灰度、流量监控——这些和业务无关。Istio 的思路：给每个 Pod 注入一个 &lt;strong&gt;Envoy 边车代理&lt;/strong&gt;，接管所有进出流量，上述能力全部在代理层实现，业务代码零侵入。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;graph TB
    subgraph 控制平面[&amp;#34;Istio 控制平面（istiod）&amp;#34;]
        Pilot[配置下发&amp;lt;br/&amp;gt;流量规则]
        Citadel[证书管理&amp;lt;br/&amp;gt;mTLS]
    end
    subgraph 数据平面
        subgraph PodA[&amp;#34;Pod A&amp;#34;]
            App1[业务容器] --- E1[Envoy 边车]
        end
        subgraph PodB[&amp;#34;Pod B&amp;#34;]
            App2[业务容器] --- E2[Envoy 边车]
        end
    end
    Pilot -.-&amp;gt;|xDS 配置下发| E1
    Pilot -.-&amp;gt;|xDS 配置下发| E2
    E1 &amp;lt;--&amp;gt;|&amp;#34;mTLS 加密流量&amp;lt;br/&amp;gt;（应用无感知）&amp;#34;| E2&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;核心能力速览：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;流量管理&lt;/strong&gt;：VirtualService + DestinationRule 实现按权重灰度（v1 90% / v2 10%）、按 Header 路由、超时重试、熔断&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;安全&lt;/strong&gt;：服务间自动 mTLS 加密 + 身份认证（AuthorizationPolicy）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可观测&lt;/strong&gt;：不用改代码就拿到全链路指标、调用拓扑、访问日志&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;入口&lt;/strong&gt;：Istio Gateway 替代/补充原生 Ingress，作为网格的南北向入口&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;避坑点（Istio 坑不少，挑最重要的）：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;边车有成本&lt;/strong&gt;：每个 Pod 多一份 Envoy 的 CPU/内存（默认 requests 约 100m/128Mi），上千 Pod 规模要算这笔账，必要时调小。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sidecar 启动顺序&lt;/strong&gt;：业务容器可能比 Envoy 先起来导致启动瞬间网络不通（现在 &lt;code&gt;holdApplicationUntilProxyStarts&lt;/code&gt; 可解）；Job 类任务跑完 Envoy 不退导致 Job 永不结束，需要显式退出或关掉注入。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;协议识别&lt;/strong&gt;：Service 端口名要带协议前缀（&lt;code&gt;name: http-xxx&lt;/code&gt;），否则 Istio 按 TCP 处理，七层能力全部失效。这是网格内路由不生效的第一嫌疑。&lt;/li&gt;
&lt;li&gt;排障三板斧：&lt;code&gt;istioctl analyze&lt;/code&gt;（静态检查配置）、&lt;code&gt;istioctl proxy-config&lt;/code&gt;（看 Envoy 实际生效配置）、Envoy 的 &lt;code&gt;:15000/stats&lt;/code&gt; 和 &lt;code&gt;:15000/clusters&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;新人别一上来就上全量 Istio。先在非核心 namespace 开注入练手，理解 VirtualService 再说。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&#34;十云上落地阿里云-ack-为主aws-eks-对照&#34;&gt;十、云上落地：阿里云 ACK 为主，AWS EKS 对照&lt;/h2&gt;
&lt;p&gt;自己从零搭一套生产级 K8s（etcd 高可用、证书、网络插件）成本极高，生产环境几乎都用云厂商托管服务。&lt;/p&gt;
&lt;h3 id=&#34;101-阿里云-ack-关键点&#34;&gt;10.1 阿里云 ACK 关键点&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;graph TB
    subgraph 阿里云托管[&amp;#34;ACK 托管层（免费/Pro）&amp;#34;]
        MA[控制平面：apiserver/etcd/scheduler&amp;lt;br/&amp;gt;阿里云托管，SLA 保障]
    end
    subgraph 你的账号[&amp;#34;你的 VPC 内&amp;#34;]
        N1[ECS 节点池 1&amp;lt;br/&amp;gt;按量/抢占式]
        N2[ECS 节点池 2&amp;lt;br/&amp;gt;弹性伸缩 ESS]
    end
    MA --&amp;gt; N1
    MA --&amp;gt; N2
    N1 -.对接.-&amp;gt; CLB[CLB/ALB&amp;lt;br/&amp;gt;负载均衡]
    N1 -.对接.-&amp;gt; NAS[云盘 ESSD / NAS&amp;lt;br/&amp;gt;持久存储]
    N1 -.对接.-&amp;gt; SLS[SLS 日志 / ARMS 监控&amp;lt;br/&amp;gt;可观测]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;实践经验：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;网络插件选 Terway&lt;/strong&gt;：Pod 直接用 VPC 弹性网卡 IP，无 overlay 开销、conntrack 压力小，还能配 NetworkPolicy；Flannel 适合小规模简单场景。Terway 模式下&lt;strong&gt;规划 VPC 网段要留够&lt;/strong&gt;，每个 Pod 占一个真实 IP。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;节点池 + 弹性伸缩&lt;/strong&gt;：按业务波峰波谷自动扩缩节点；抢占式实例（Spot）跑无状态任务能省 70% 成本，但要容忍随时被回收。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ingress 用 ALB Ingress Controller&lt;/strong&gt;：比自建 Nginx Ingress 省心，ALB 本身按量弹性，且和 ACK 深度集成。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;日志和监控开箱即用&lt;/strong&gt;：日志服务 SLS（采集容器 stdout 和文件日志）、ARMS Prometheus 监控，别再自己搭 ELK 了。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;镜像仓库 ACR&lt;/strong&gt;：用 ACR EE（企业版）+ ACK 免密拉取插件，避免在 YAML 里配 imagePullSecret。&lt;/li&gt;
&lt;li&gt;存储选 &lt;strong&gt;CNFS/云盘 ESSD（有状态单副本）+ NAS（共享文件）+ OSS（静态资源、备份）&lt;/strong&gt; 的组合。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;102-aws-eks-速查对照&#34;&gt;10.2 AWS EKS 速查对照&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;需求&lt;/th&gt;
					&lt;th&gt;阿里云 ACK&lt;/th&gt;
					&lt;th&gt;AWS EKS&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;网络插件&lt;/td&gt;
					&lt;td&gt;Terway（VPC 网卡直连）&lt;/td&gt;
					&lt;td&gt;aws-vpc-cni（同理）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;七层入口&lt;/td&gt;
					&lt;td&gt;ALB Ingress&lt;/td&gt;
					&lt;td&gt;AWS Load Balancer Controller (ALB/NLB)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;块存储&lt;/td&gt;
					&lt;td&gt;云盘 ESSD&lt;/td&gt;
					&lt;td&gt;EBS (gp3)&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;共享文件存储&lt;/td&gt;
					&lt;td&gt;NAS&lt;/td&gt;
					&lt;td&gt;EFS&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;日志&lt;/td&gt;
					&lt;td&gt;SLS&lt;/td&gt;
					&lt;td&gt;CloudWatch&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;监控&lt;/td&gt;
					&lt;td&gt;ARMS Prometheus&lt;/td&gt;
					&lt;td&gt;Managed Prometheus / Grafana&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;镜像仓库&lt;/td&gt;
					&lt;td&gt;ACR&lt;/td&gt;
					&lt;td&gt;ECR&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;无服务器节点&lt;/td&gt;
					&lt;td&gt;虚拟节点（ECI）&lt;/td&gt;
					&lt;td&gt;Fargate&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;概念完全互通，换云只是换 Controller 和注解。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;十一典型问题排查手册&#34;&gt;十一、典型问题排查手册&lt;/h2&gt;
&lt;h3 id=&#34;111-通用排查流程&#34;&gt;11.1 通用排查流程&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;graph TD
    A[发现问题] --&amp;gt; B{Pod 状态？&amp;lt;br/&amp;gt;kubectl get pods}
    B --&amp;gt;|Pending| C[kubectl describe pod&amp;lt;br/&amp;gt;看 Events]
    C --&amp;gt; C1{原因}
    C1 --&amp;gt;|资源不足| C2[加节点/降 requests&amp;lt;br/&amp;gt;或开弹性伸缩]
    C1 --&amp;gt;|存储挂载失败| C3[检查 PVC 绑定/可用区]
    C1 --&amp;gt;|镜像拉取失败| C4[ImagePullBackOff：查镜像名/凭证/网络]
    B --&amp;gt;|CrashLoopBackOff| D[kubectl logs --previous&amp;lt;br/&amp;gt;看上一个容器的临终日志]
    D --&amp;gt; D1{原因}
    D1 --&amp;gt;|应用自身报错| D2[修代码/配置]
    D1 --&amp;gt;|Exit 137| D3[OOMKilled：调大 memory limit&amp;lt;br/&amp;gt;或查内存泄漏]
    D1 --&amp;gt;|Exit 143| D4[被优雅终止：查探针/滚动更新]
    B --&amp;gt;|Running 但访问异常| E[分层验证]
    E --&amp;gt; E1[1. 进 Pod 内 curl localhost 通吗？]
    E1 --&amp;gt; E2[2. curl Pod IP 通吗？]
    E2 --&amp;gt; E3[3. curl Service ClusterIP 通吗？&amp;lt;br/&amp;gt;查 Endpoints 是否有后端]
    E3 --&amp;gt; E4[4. Ingress 域名通吗？&amp;lt;br/&amp;gt;查 Controller 日志]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;112-高频问题速查表&#34;&gt;11.2 高频问题速查表&lt;/h3&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;ImagePullBackOff&lt;/td&gt;
					&lt;td&gt;镜像名/tag 错、私有仓库无凭证、节点无公网&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;describe pod&lt;/code&gt; 看 Events 报错原文&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;CrashLoopBackOff&lt;/td&gt;
					&lt;td&gt;配置错、依赖没起来、探针误杀&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;kubectl logs --previous&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;OOMKilled (137)&lt;/td&gt;
					&lt;td&gt;内存 limit 太小或泄漏&lt;/td&gt;
					&lt;td&gt;看监控曲线，调 limit；Java 服务注意堆外内存&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Pod 一直 Pending&lt;/td&gt;
					&lt;td&gt;资源不够、PVC 未绑定、污点/亲和性&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;describe pod&lt;/code&gt; 看调度失败原因&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;服务间偶发超时&lt;/td&gt;
					&lt;td&gt;conntrack 满、DNS 慢、TIME_WAIT 耗尽&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;ss -s&lt;/code&gt;、CoreDNS 日志、查连接池配置&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;滚动更新后 502&lt;/td&gt;
					&lt;td&gt;没配 readinessProbe / 没处理 SIGTERM 优雅退出&lt;/td&gt;
					&lt;td&gt;配探针 + preStop + 应用优雅关闭&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;ConfigMap 改了不生效&lt;/td&gt;
					&lt;td&gt;环境变量注入 / subPath 挂载&lt;/td&gt;
					&lt;td&gt;重启 Pod 或改为目录挂载&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;跨可用区挂载失败&lt;/td&gt;
					&lt;td&gt;云盘和节点不在同一 AZ&lt;/td&gt;
					&lt;td&gt;WaitForFirstConsumer + 拓扑约束&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;113-优雅退出滚动更新不断流的完整姿势&#34;&gt;11.3 优雅退出：滚动更新不断流的完整姿势&lt;/h3&gt;
&lt;p&gt;Pod 被删除时的标准流程（很多人只知道一半）：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;sequenceDiagram
    participant K as kubelet
    participant P as Pod
    participant EP as Endpoints

    K-&amp;gt;&amp;gt;EP: 把 Pod 从 Service 摘除（不再接新流量）
    K-&amp;gt;&amp;gt;P: 执行 preStop 钩子（如 sleep 5，等摘流量生效）
    K-&amp;gt;&amp;gt;P: 发送 SIGTERM
    P-&amp;gt;&amp;gt;P: 应用应：停止接新请求，处理完存量请求后退出
    Note over K,P: 超过 terminationGracePeriodSeconds（默认30s）
    K-&amp;gt;&amp;gt;P: SIGKILL 强杀&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;三个缺一不可：readinessProbe 保证新 Pod ready 才切流量；preStop/优雅关闭保证老 Pod 处理完存量请求；&lt;code&gt;terminationGracePeriodSeconds&lt;/code&gt; 给够时间。Java/Go 服务请确认框架注册了 SIGTERM 处理器（Spring Boot 的 &lt;code&gt;server.shutdown=graceful&lt;/code&gt;、Go 的 &lt;code&gt;signal.Notify&lt;/code&gt;）。&lt;/p&gt;
&lt;h3 id=&#34;114-kubectl-排障速查&#34;&gt;11.4 kubectl 排障速查&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;kubectl get pods -o wide -n &amp;lt;ns&amp;gt;          &lt;span style=&#34;color:#75715e&#34;&gt;# 看状态和所在节点&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;kubectl describe pod &amp;lt;pod&amp;gt; -n &amp;lt;ns&amp;gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# 看 Events（排障第一步）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;kubectl logs &amp;lt;pod&amp;gt; -c &amp;lt;container&amp;gt; --previous   &lt;span style=&#34;color:#75715e&#34;&gt;# 崩溃前的日志&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;kubectl get endpoints &amp;lt;svc&amp;gt; -n &amp;lt;ns&amp;gt;       &lt;span style=&#34;color:#75715e&#34;&gt;# Service 后面到底有没有 Pod&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;kubectl exec -it &amp;lt;pod&amp;gt; -- sh              &lt;span style=&#34;color:#75715e&#34;&gt;# 进容器内验证网络&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;kubectl run debug --rm -it --image&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;busybox:1.36 -- sh   &lt;span style=&#34;color:#75715e&#34;&gt;# 临时网络调试 Pod&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;kubectl top pod / kubectl top node        &lt;span style=&#34;color:#75715e&#34;&gt;# 资源占用&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;kubectl get events --sort-by&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;.lastTimestamp -n &amp;lt;ns&amp;gt;     &lt;span style=&#34;color:#75715e&#34;&gt;# 按时间看事件&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;十二cicdjenkins-与-k8s-打通实现自动化部署与验证&#34;&gt;十二、CI/CD：Jenkins 与 K8s 打通，实现自动化部署与验证&lt;/h2&gt;
&lt;p&gt;手工 &lt;code&gt;kubectl apply&lt;/code&gt; 只适合学习。生产环境的标准做法是把「构建 → 推镜像 → 部署 → 验证 → 失败回滚」串成流水线，代码合并后自动完成发布。&lt;/p&gt;
&lt;h3 id=&#34;121-整体流水线长什么样&#34;&gt;12.1 整体流水线长什么样&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;graph LR
    Dev[开发者 git push] --&amp;gt; Hook[Webhook 触发 Jenkins]
    Hook --&amp;gt; Build[阶段1: 构建&amp;lt;br/&amp;gt;单测 + Docker 镜像]
    Build --&amp;gt; Push[阶段2: 推送镜像&amp;lt;br/&amp;gt;到 ACR/ECR&amp;lt;br/&amp;gt;tag = git commit]
    Push --&amp;gt; Deploy[阶段3: 部署&amp;lt;br/&amp;gt;kubectl set image&amp;lt;br/&amp;gt;更新 K8s]
    Deploy --&amp;gt; Verify[阶段4: 验证&amp;lt;br/&amp;gt;rollout status + 冒烟测试]
    Verify --&amp;gt;|成功| Done[发布完成&amp;lt;br/&amp;gt;钉钉/邮件通知]
    Verify --&amp;gt;|失败| RB[自动回滚&amp;lt;br/&amp;gt;rollout undo] --&amp;gt; Alarm[告警通知]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;关键认知：&lt;strong&gt;K8s 侧不需要装任何 Jenkins 插件或 Agent 也能被部署&lt;/strong&gt;——Jenkins 只要有目标集群的 kubeconfig（访问凭证），用 &lt;code&gt;kubectl&lt;/code&gt; 就能驱动 apiserver 完成一切。打通的本质就两件事：凭证怎么管、流水线脚本怎么写。&lt;/p&gt;
&lt;h3 id=&#34;122-jenkins-的两种部署形态&#34;&gt;12.2 Jenkins 的两种部署形态&lt;/h3&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;Jenkins 在集群外（独立服务器/另一集群）&lt;/td&gt;
					&lt;td&gt;通过 kubeconfig 远程操作业务集群&lt;/td&gt;
					&lt;td&gt;一套 Jenkins 管多个集群，最常见&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Jenkins 跑在 K8s 集群内&lt;/td&gt;
					&lt;td&gt;配合 Kubernetes 插件，每次构建动态拉起一个 Pod 作为构建 agent，用完即销毁&lt;/td&gt;
					&lt;td&gt;构建任务多、想弹性利用集群资源&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;graph TB
    subgraph Jenkins侧[&amp;#34;Jenkins（集群外或集群内）&amp;#34;]
        J[Jenkins Master]
        C1[凭据1: kubeconfig&amp;lt;br/&amp;gt;Secret file 类型]
        C2[凭据2: ACR 账号&amp;lt;br/&amp;gt;Username/Password 类型]
        J --&amp;gt; C1
        J --&amp;gt; C2
    end
    subgraph 阿里云[&amp;#34;阿里云&amp;#34;]
        J --&amp;gt;|docker push| ACR[ACR 镜像仓库]
        J --&amp;gt;|&amp;#34;kubectl（走内网 API Server 端点）&amp;#34;| API[ACK apiserver]
        API --&amp;gt; Pod[滚动更新业务 Pod]
        Pod --&amp;gt;|免密拉取| ACR
    end&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;推荐做法：Jenkins 与 ACK 在&lt;strong&gt;同一 VPC 内&lt;/strong&gt;，kubectl 直接走 API Server 的&lt;strong&gt;内网端点&lt;/strong&gt;（安全且免公网流量）；镜像仓库用 ACR 企业版 + ACK 免密拉取，业务侧零凭证。&lt;/p&gt;
&lt;h3 id=&#34;123-最小权限的部署凭证别把-admin-kubeconfig-给-jenkins&#34;&gt;12.3 最小权限的部署凭证：别把 admin kubeconfig 给 Jenkins&lt;/h3&gt;
&lt;p&gt;这是 CI/CD 安全的第一课。给 Jenkins 一个&lt;strong&gt;只能操作特定 namespace、只能改 Deployment&lt;/strong&gt; 的 ServiceAccount：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;apiVersion&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;v1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;kind&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;ServiceAccount&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;metadata&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;jenkins-deployer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;namespace&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;prod&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Role 只在 prod namespace 内生效&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;apiVersion&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;rbac.authorization.k8s.io/v1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;kind&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Role&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;metadata&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;deployer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;namespace&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;prod&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;rules&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#f92672&#34;&gt;apiGroups&lt;/span&gt;: [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;apps&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;resources&lt;/span&gt;: [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;deployments&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;verbs&lt;/span&gt;: [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;get&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;list&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;watch&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;patch&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;update&amp;#34;&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;apiVersion&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;rbac.authorization.k8s.io/v1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;kind&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;RoleBinding&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;metadata&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;jenkins-deployer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;namespace&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;prod&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;subjects&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - &lt;span style=&#34;color:#f92672&#34;&gt;kind&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;ServiceAccount&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;jenkins-deployer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;namespace&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;prod&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;roleRef&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;kind&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Role&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;deployer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;apiGroup&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;rbac.authorization.k8s.io&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;然后为这个 SA 生成 token，做成只含该 token 的 kubeconfig，存进 Jenkins 的 &lt;strong&gt;Secret file 凭据&lt;/strong&gt;。好处：凭证泄露也只影响一个 namespace 的 Deployment，且可以随时 &lt;code&gt;kubectl delete rolebinding&lt;/code&gt; 吊销。&lt;/p&gt;
&lt;h3 id=&#34;124-完整-jenkinsfile-示例&#34;&gt;12.4 完整 Jenkinsfile 示例&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-groovy&#34; data-lang=&#34;groovy&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pipeline &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    agent any
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    environment &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        IMAGE     &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;registry.cn-hangzhou.aliyuncs.com/mycompany/order-svc&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        TAG       &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;${env.GIT_COMMIT.take(8)}&amp;#34;&lt;/span&gt;   &lt;span style=&#34;color:#75715e&#34;&gt;// 用 git commit 做 tag，可回滚可追溯
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        KUBECONFIG &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; credentials&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;ack-prod-kubeconfig&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;   &lt;span style=&#34;color:#75715e&#34;&gt;// Secret file 凭据
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    stages &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        stage&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;构建&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            steps &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                sh &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;mvn -q test&amp;#39;&lt;/span&gt;                       &lt;span style=&#34;color:#75715e&#34;&gt;// 先跑单测，挂了直接终止
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                sh &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;docker build -t ${IMAGE}:${TAG} .&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        stage&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;推送镜像&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            steps &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                withCredentials&lt;span style=&#34;color:#f92672&#34;&gt;([&lt;/span&gt;usernamePassword&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    credentialsId: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;acr-account&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    usernameVariable: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;U&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;,&lt;/span&gt; passwordVariable: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;P&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)])&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    sh &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;echo $P | docker login registry.cn-hangzhou.aliyuncs.com -u $U --password-stdin&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                    sh &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;docker push ${IMAGE}:${TAG}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        stage&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;部署到 ACK&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            steps &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                sh &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kubectl --kubeconfig=$KUBECONFIG -n prod \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;                    set image deployment/order-svc order-svc=${IMAGE}:${TAG}&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        stage&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;验证&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            steps &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#75715e&#34;&gt;// 阻塞等待滚动更新完成；超时/失败会非零退出
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                sh &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kubectl --kubeconfig=$KUBECONFIG -n prod \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;                    rollout status deployment/order-svc --timeout=300s&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#75715e&#34;&gt;// 冒烟测试：走内网 SLB 打健康检查和关键接口
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                sh &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;curl -fsS --retry 5 --retry-delay 3 \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;                    http://order-svc-internal.prod.svc.cluster.local/healthz || exit 1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    post &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        failure &lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;// 部署验证失败自动回滚到上一个版本
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            sh &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;kubectl --kubeconfig=$KUBECONFIG -n prod \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;                rollout undo deployment/order-svc || true&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;125-验证环节的正确姿势&#34;&gt;12.5 「验证」环节的正确姿势&lt;/h3&gt;
&lt;p&gt;很多流水线只做到 &lt;code&gt;kubectl apply&lt;/code&gt; 就算「发布成功」，这是自欺欺人。&lt;code&gt;apply&lt;/code&gt; 返回成功只代表 apiserver 收下了 YAML，Pod 起不起得来是另一回事。可靠的验证链：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;rollout status 阻塞等待&lt;/strong&gt;：确认所有新副本 ready（背后靠的就是 readinessProbe——再次体现探针的重要性）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;冒烟测试&lt;/strong&gt;：对真实入口打 &lt;code&gt;/healthz&lt;/code&gt; 和一两个核心业务接口，确认「能起来」且「能干活」。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;失败自动回滚&lt;/strong&gt;：&lt;code&gt;rollout undo&lt;/code&gt; 依赖旧 ReplicaSet 还在（&lt;code&gt;revisionHistoryLimit&lt;/code&gt; 别设 0）且镜像 tag 可追溯——这就是前面说「不要用 latest」的根本原因。&lt;/li&gt;
&lt;li&gt;更严谨的做法是&lt;strong&gt;灰度验证&lt;/strong&gt;：先用 Istio 把 5% 流量切到新版本观察指标，确认无误再全量（见第九章）。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;126-cicd-避坑清单&#34;&gt;12.6 CI/CD 避坑清单&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;镜像 tag 必须唯一可追溯&lt;/strong&gt;：git commit 短哈希或构建号，杜绝 &lt;code&gt;latest&lt;/code&gt;，否则回滚时根本不知道该回滚到哪个镜像。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;凭据最小化 + 分环境&lt;/strong&gt;：dev/staging/prod 用不同的 SA 和 Jenkins 凭据，prod 的部署动作加人工审批（Jenkins 的 &lt;code&gt;input&lt;/code&gt; 步骤）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;声明式优先&lt;/strong&gt;：服务变多后，把 &lt;code&gt;kubectl set image&lt;/code&gt; 换成 Helm/Kustomize（YAML 也进 Git 仓库，可审计可 diff）；再进一步上 &lt;strong&gt;GitOps（ArgoCD/Flux）&lt;/strong&gt;——Jenkins 只负责构建推镜像，部署由集群内的 ArgoCD 从 Git 仓库自动同步，Jenkins 不再需要生产集群的任何凭证，安全性大幅提升。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Jenkins 到集群的网络&lt;/strong&gt;：kubectl 走内网 API Server 端点；如果 Jenkins 在另一个 VPC，用云企业网/对等连接打通，不要把 API Server 暴露公网给 Jenkins 用。&lt;/li&gt;
&lt;li&gt;构建产物（镜像）与部署配置分离管理，避免「同一个 tag 被覆盖推送」导致回滚失效——ACR 里给 prod 仓库开&lt;strong&gt;镜像 tag 不可变&lt;/strong&gt;（immutable）开关。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&#34;十三学习路线建议&#34;&gt;十三、学习路线建议&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;第一周&lt;/strong&gt;：本地装 minikube 或 kind，把 Deployment/Service/ConfigMap 各玩一遍，亲手制造一次 CrashLoopBackOff 并修好它。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;第二周&lt;/strong&gt;：搞懂网络——Pod 网络、Service 转发（iptables）、Ingress、NetworkPolicy 内外网隔离，配合 &lt;code&gt;tcpdump&lt;/code&gt;/&lt;code&gt;ss&lt;/code&gt; 在容器里抓包看真实流量。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;第三周&lt;/strong&gt;：上云。开一套阿里云 ACK（按量付费，玩完就删），跑通「ACR 推镜像 → ACK 部署 → ALB Ingress 暴露 → NAS 挂共享盘 → SLS 看日志」全流程。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;第四周&lt;/strong&gt;：打通 CI/CD。用 Jenkins + 最小权限 SA 实现「推代码 → 自动构建 → 自动部署 → rollout 验证 → 失败回滚」完整流水线。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;进阶&lt;/strong&gt;：Helm 包管理、HPA 自动扩缩容、Istio 灰度发布、GitOps（ArgoCD）。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;最后送一句《Kubernetes 权威指南》反复强调的心法：&lt;strong&gt;K8s 的一切都是声明式的——你描述「我要什么」，控制器负责「做到」&lt;/strong&gt;。排查问题时永远先问：期望状态（YAML/Spec）是什么？实际状态（Status/Events）是什么？两者的差距就是答案所在。&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;参考资料：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;《Kubernetes 权威指南：从 Docker 到 Kubernetes 实践全接触（第 4 版）》龚正 等&lt;/li&gt;
&lt;li&gt;《Kubernetes in Action》Marko Lukša&lt;/li&gt;
&lt;li&gt;《Unix 网络编程 卷1》W. Richard Stevens（网络排障内功）&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kubernetes.io/zh-cn/docs/&#34;&gt;Kubernetes 官方文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://help.aliyun.com/product/85222.html&#34;&gt;阿里云 ACK 文档&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
</description>
    </item>
    <item>
      <title> TCP/IP 学习总结与避坑指南</title>
      <link>https://ftmao.com/blog/bookstore/tcp-ip-illustrated-notes/</link>
      <pubDate>Sat, 09 Dec 2017 10:00:00 +0800</pubDate>
      <guid>https://ftmao.com/blog/bookstore/tcp-ip-illustrated-notes/</guid>
      <description>&lt;h1 id=&#34;tcpip-学习总结与避坑指南&#34;&gt;TCP/IP 学习总结与避坑指南&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;最近华为项目交付碰到各种头大的网络问题，现在整理下TCP/IP相关知识。参考书籍：W. Richard Stevens《TCP/IP 详解 卷1：协议》、W. Richard Stevens《Unix 网络编程 卷1：套接字联网 API》&lt;br&gt;
目标读者：刚接触网络编程，或者学了很多概念但总觉得「协议栈串不起来」「代码一跑就掉坑」的同学。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;TCP/IP 不是一门「背完就能会」的技术。它由一整套分层协议组成，每一层只关心自己的事情，又通过严格定义的头部把信息交给下一层。理解这套分层思维，是看懂网络报文、写出稳定网络程序、排查线上连接问题的第一步。&lt;/p&gt;
&lt;p&gt;这篇文章不会把所有 RFC 都讲一遍（那是 1000 多页书做的事），而是帮你建立&lt;strong&gt;主干知识框架&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TCP/IP 协议栈为什么要分层？数据是怎么一层层包起来的？&lt;/li&gt;
&lt;li&gt;IP、TCP、UDP、ARP、ICMP、DNS 这些协议各自解决什么问题？&lt;/li&gt;
&lt;li&gt;Unix Socket 编程的核心 API 与调用顺序是什么？&lt;/li&gt;
&lt;li&gt;写网络程序最容易踩哪些坑，怎么避开？&lt;/li&gt;
&lt;li&gt;遇到连接失败、卡顿、端口耗尽这些问题，该按什么思路排查？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;读完之后，你应该能看懂 Wireshark 里的大部分常见报文，也能独立写出稳定的 TCP 客户端/服务端，并具备基础的线上网络问题排查能力。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一tcpip-协议栈为什么必须分层&#34;&gt;一、TCP/IP 协议栈：为什么必须分层？&lt;/h2&gt;
&lt;p&gt;网络通信的复杂度非常高：不同的物理介质、不同的操作系统、不同的应用程序要在全球范围内交换数据。如果不分层，每一台设备都要同时处理「电信号怎么传」「数据怎么路由」「传输可不可靠」「应用数据什么意思」所有问题。&lt;/p&gt;
&lt;p&gt;分层的目的就是&lt;strong&gt;关注点分离&lt;/strong&gt;：每一层只解决本层的问题，向上层提供服务，把复杂问题拆成可管理的小块。&lt;/p&gt;
&lt;h3 id=&#34;11-osi-七层模型-vs-tcpip-四层模型&#34;&gt;1.1 OSI 七层模型 vs TCP/IP 四层模型&lt;/h3&gt;
&lt;p&gt;教学中常用 OSI 七层模型，但互联网实际运行的是 TCP/IP 四层模型。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;graph LR
    subgraph OSI七层模型
        A7[7 应用层] --&amp;gt; A6[6 表示层]
        A6 --&amp;gt; A5[5 会话层]
        A5 --&amp;gt; A4[4 传输层]
        A4 --&amp;gt; A3[3 网络层]
        A3 --&amp;gt; A2[2 数据链路层]
        A2 --&amp;gt; A1[1 物理层]
    end

    subgraph TCP/IP四层模型
        B4[应用层&amp;lt;br/&amp;gt;HTTP/FTP/DNS/SMTP] --&amp;gt; B3[传输层&amp;lt;br/&amp;gt;TCP/UDP]
        B3 --&amp;gt; B2[网络层&amp;lt;br/&amp;gt;IP/ICMP/IGMP]
        B2 --&amp;gt; B1[网络接口层&amp;lt;br/&amp;gt;以太网/WiFi/PPP]
    end

    A7 -.对应.-&amp;gt; B4
    A6 -.对应.-&amp;gt; B4
    A5 -.对应.-&amp;gt; B4
    A4 -.对应.-&amp;gt; B3
    A3 -.对应.-&amp;gt; B2
    A2 -.对应.-&amp;gt; B1
    A1 -.对应.-&amp;gt; B1&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;TCP/IP 层&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;HTTP、DNS、FTP、SMTP、SSH&lt;/td&gt;
					&lt;td&gt;应用程序之间「说什么」&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;传输层&lt;/td&gt;
					&lt;td&gt;TCP、UDP&lt;/td&gt;
					&lt;td&gt;进程到进程的通信，可靠或高效传输&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;网络层&lt;/td&gt;
					&lt;td&gt;IP、ICMP、IGMP、路由协议&lt;/td&gt;
					&lt;td&gt;主机到主机的寻址与路由&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;网络接口层&lt;/td&gt;
					&lt;td&gt;以太网、WiFi、ARP、PPP&lt;/td&gt;
					&lt;td&gt;相邻设备之间的物理/逻辑传输&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;新手容易混淆的点&lt;/strong&gt;：TCP/IP 里的「应用层」实际上对应了 OSI 的应用层、表示层、会话层三层。不要死磕七层，实际工程里四层模型更常用。&lt;/p&gt;
&lt;h3 id=&#34;12-数据封装与解封装&#34;&gt;1.2 数据封装与解封装&lt;/h3&gt;
&lt;p&gt;每一层都会给上一层的数据加一个「头部」，然后交给下一层。接收方则逐层去掉头部，把数据交给上层。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TB
    subgraph 发送方
        A[应用数据] --&amp;gt;|&amp;#34;应用层封装&amp;#34;| B[&amp;#34;应用层头部 + 应用数据&amp;#34;]
        B --&amp;gt;|&amp;#34;传输层封装&amp;#34;| C[&amp;#34;TCP/UDP 头部 + 应用层数据&amp;#34;]
        C --&amp;gt;|&amp;#34;网络层封装&amp;#34;| D[&amp;#34;IP 头部 + TCP 数据段&amp;#34;]
        D --&amp;gt;|&amp;#34;链路层封装&amp;#34;| E[&amp;#34;以太网头部 + IP 数据报 + 以太网尾部&amp;#34;]
    end

    E --&amp;gt;|&amp;#34;比特流在物理介质传输&amp;#34;| F

    subgraph 接收方
        F[&amp;#34;以太网帧&amp;#34;] --&amp;gt;|&amp;#34;链路层解封装&amp;#34;| G[&amp;#34;IP 数据报&amp;#34;]
        G --&amp;gt;|&amp;#34;网络层解封装&amp;#34;| H[&amp;#34;TCP/UDP 数据段&amp;#34;]
        H --&amp;gt;|&amp;#34;传输层解封装&amp;#34;| I[&amp;#34;应用层数据&amp;#34;]
        I --&amp;gt;|&amp;#34;应用层处理&amp;#34;| J[交给对应进程]
    end&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;关键概念&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MTU（Maximum Transmission Unit）&lt;/strong&gt;：链路层帧能承载的最大数据量，以太网常见值是 1500 字节。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MSS（Maximum Segment Size）&lt;/strong&gt;：TCP 一次能发送的最大数据段，通常 = MTU - IP 头 - TCP 头，以太网常见 1460 字节。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;分片（Fragmentation）&lt;/strong&gt;：当 IP 数据报超过链路 MTU 时，IP 层会把它切成多个片。TCP 一般会通过 MSS 避免分片，UDP 则容易触发分片。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;避坑技巧&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不要随意修改 MTU，VPN/隧道场景特别容易出现「大数据包被静默丢弃」的问题。&lt;/li&gt;
&lt;li&gt;UDP 应用如果要传输大报文，建议在应用层自己拆包，不要让 IP 层分片。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二链路层与-arp同一局域网怎么找到对方&#34;&gt;二、链路层与 ARP：同一局域网怎么找到对方？&lt;/h2&gt;
&lt;p&gt;链路层负责&lt;strong&gt;相邻节点&lt;/strong&gt;之间的数据传输。在以太网里，设备用 MAC 地址标识，交换机根据 MAC 地址转发帧。&lt;/p&gt;
&lt;h3 id=&#34;21-以太网帧结构&#34;&gt;2.1 以太网帧结构&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+----------------+----------------+----------------+----------------+----------------+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| 目的 MAC 6B    | 源 MAC 6B      | 类型 2B        | 数据 46~1500B  | FCS 4B         |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+----------------+----------------+----------------+----------------+----------------+&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MAC 地址&lt;/strong&gt;：48 位，全球唯一（理论上），用于局域网内定位网卡。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;类型字段&lt;/strong&gt;：例如 &lt;code&gt;0x0800&lt;/code&gt; 表示上层是 IP，&lt;code&gt;0x0806&lt;/code&gt; 表示 ARP。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FCS（Frame Check Sequence）&lt;/strong&gt;：帧校验序列，检测传输过程中的比特错误。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;22-arpip-地址--mac-地址&#34;&gt;2.2 ARP：IP 地址 → MAC 地址&lt;/h3&gt;
&lt;p&gt;ARP（Address Resolution Protocol）解决的是「知道对方 IP，但不知道对方 MAC」的问题。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;sequenceDiagram
    participant A as 主机 A&amp;lt;br/&amp;gt;192.168.1.10
    participant B as 主机 B&amp;lt;br/&amp;gt;192.168.1.20

    A-&amp;gt;&amp;gt;B: ARP 请求：谁的 IP 是 192.168.1.20？请告诉我你的 MAC
    Note over A,B: 广播帧，局域网内所有主机收到
    B-&amp;gt;&amp;gt;A: ARP 应答：我是 192.168.1.20，MAC 是 xx:xx:xx:xx:xx:xx
    Note over A,B: 单播帧，只有 A 收到&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;ARP 表会缓存一段时间：&lt;code&gt;arp -a&lt;/code&gt; 可以查看本机 ARP 缓存。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;避坑技巧&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ARP 只在&lt;strong&gt;同一二层网络&lt;/strong&gt;（同一广播域）有效。跨网段通信时，主机把报文发给网关，由网关继续转发。&lt;/li&gt;
&lt;li&gt;网关配错是新手常见问题：如果默认网关不在同一子网，ARP 请求会失败，数据根本发不出去。&lt;/li&gt;
&lt;li&gt;ARP 欺骗/中间人攻击在局域网内存在，敏感环境要开启动态 ARP 检测（DAI）或静态绑定。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;三ip-协议主机到主机的寻址与路由&#34;&gt;三、IP 协议：主机到主机的寻址与路由&lt;/h2&gt;
&lt;p&gt;IP（Internet Protocol）是网络层的核心，负责把数据从源主机送到目的主机。它&lt;strong&gt;不保证可靠、不保证有序&lt;/strong&gt;，这些由 TCP 或应用层自己处理。&lt;/p&gt;
&lt;h3 id=&#34;31-ipv4-头部核心字段&#34;&gt;3.1 IPv4 头部核心字段&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 0                   1                   2                   3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|Version|  IHL  |Type of Service|          Total Length         |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|         Identification        |Flags|      Fragment Offset    |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|  Time to Live |    Protocol   |         Header Checksum       |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|                       Source Address                          |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|                    Destination Address                        |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|                    Options                    |    Padding    |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;关键字段含义：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Version&lt;/strong&gt;：IPv4 填 4，IPv6 填 6。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IHL（Header Length）&lt;/strong&gt;：头部长度，单位是 4 字节。没有选项时最小是 5，即 20 字节。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Total Length&lt;/strong&gt;：整个 IP 数据报的长度，最大 65535 字节。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Identification / Flags / Fragment Offset&lt;/strong&gt;：用于分片和重组。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TTL（Time to Live）&lt;/strong&gt;：每经过一个路由器减 1，到 0 被丢弃，防止报文在网络里无限循环。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Protocol&lt;/strong&gt;：上层协议类型。6 = TCP，17 = UDP，1 = ICMP，等等。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Source/Destination Address&lt;/strong&gt;：源 IP 和目的 IP。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;32-ip-地址子网掩码与-cidr&#34;&gt;3.2 IP 地址、子网掩码与 CIDR&lt;/h3&gt;
&lt;p&gt;IP 地址 = 网络号 + 主机号。子网掩码用来划分这两部分。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;IP 地址：    192.168.1.100   → 11000000.10101000.00000001.01100100
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;子网掩码：   255.255.255.0   → 11111111.11111111.11111111.00000000
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;网络号：     192.168.1.0     → 前 24 位
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;主机号：     0.0.0.100       → 后 8 位&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;CIDR 表示法：&lt;code&gt;192.168.1.0/24&lt;/code&gt;，斜杠后面的数字表示网络号位数。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;判断两台主机是否在同一子网&lt;/strong&gt;：用各自的 IP 和子网掩码做按位与，得到网络号，网络号相同就在同一子网。&lt;/p&gt;
&lt;h3 id=&#34;33-路由基础&#34;&gt;3.3 路由基础&lt;/h3&gt;
&lt;p&gt;当目的 IP 不在本子网时，主机会把报文发给&lt;strong&gt;默认网关&lt;/strong&gt;（Default Gateway）。路由器根据路由表决定下一跳。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    A[主机 A&amp;lt;br/&amp;gt;192.168.1.10/24] --&amp;gt;|&amp;#34;目的 IP 不在同一子网&amp;#34;| R[路由器&amp;lt;br/&amp;gt;192.168.1.1]
    R --&amp;gt;|&amp;#34;查路由表&amp;#34;| B[主机 B&amp;lt;br/&amp;gt;10.0.0.5/24]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;常用查看命令：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Linux/macOS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip route show        &lt;span style=&#34;color:#75715e&#34;&gt;# 查看路由表&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;route -n             &lt;span style=&#34;color:#75715e&#34;&gt;# 旧命令&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Windows&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;route print&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;避坑技巧&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;配置静态 IP 时，最容易漏掉或配错的就是&lt;strong&gt;子网掩码&lt;/strong&gt;和&lt;strong&gt;默认网关&lt;/strong&gt;。只配 IP 不配上两者，通常只能 ping 通同网段。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/24&lt;/code&gt; 和 &lt;code&gt;/16&lt;/code&gt; 的区别不只是数字大小，它决定了网络规模和可用主机数。&lt;code&gt;/24&lt;/code&gt; 有 254 个可用主机地址，&lt;code&gt;/16&lt;/code&gt; 有 65534 个。&lt;/li&gt;
&lt;li&gt;路由表顺序很重要：更具体的子网（前缀更长）优先于默认路由。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;四icmpip-的诊断助手&#34;&gt;四、ICMP：IP 的「诊断助手」&lt;/h2&gt;
&lt;p&gt;ICMP（Internet Control Message Protocol）本身不传输用户数据，而是用于&lt;strong&gt;传递控制消息和诊断信息&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;41-ping-原理&#34;&gt;4.1 Ping 原理&lt;/h3&gt;
&lt;p&gt;Ping 使用 ICMP Echo Request 和 Echo Reply。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;sequenceDiagram
    participant A as 主机 A
    participant B as 主机 B

    A-&amp;gt;&amp;gt;B: ICMP Echo Request
    Note over A,B: 携带标识符和序列号
    B-&amp;gt;&amp;gt;A: ICMP Echo Reply
    Note over A,B: A 根据往返时间计算延迟&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;Ping 不通不一定是对端关机，可能是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;防火墙拦截了 ICMP&lt;/li&gt;
&lt;li&gt;路由不可达&lt;/li&gt;
&lt;li&gt;对端 ARP 表异常&lt;/li&gt;
&lt;li&gt;本机默认网关配错&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;42-traceroute-原理&#34;&gt;4.2 Traceroute 原理&lt;/h3&gt;
&lt;p&gt;Traceroute 利用 TTL 递增或端口不可达来追踪路径。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    A[主机] --&amp;gt;|&amp;#34;TTL=1&amp;#34;| R1[路由器 1]
    R1 --&amp;gt;|&amp;#34;TTL 超时，返回 ICMP Time Exceeded&amp;#34;| A
    A --&amp;gt;|&amp;#34;TTL=2&amp;#34;| R2[路由器 2]
    R2 --&amp;gt;|&amp;#34;TTL 超时，返回 ICMP Time Exceeded&amp;#34;| A
    A --&amp;gt;|&amp;#34;TTL=3&amp;#34;| B[目标主机]
    B --&amp;gt;|&amp;#34;端口不可达 / Echo Reply&amp;#34;| A&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;避坑技巧&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;有些路由器配置了「不回应 ICMP Time Exceeded」，Traceroute 会显示 &lt;code&gt;* * *&lt;/code&gt;，不代表网络不通。&lt;/li&gt;
&lt;li&gt;防火墙可能会阻断 Traceroute 的 UDP 探测端口，换 &lt;code&gt;-I&lt;/code&gt;（ICMP）或 &lt;code&gt;-T&lt;/code&gt;（TCP）模式可能成功。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;五udp简单高效不可靠&#34;&gt;五、UDP：简单、高效、不可靠&lt;/h2&gt;
&lt;p&gt;UDP（User Datagram Protocol）提供&lt;strong&gt;无连接、不可靠、面向数据报&lt;/strong&gt;的传输服务。&lt;/p&gt;
&lt;h3 id=&#34;51-udp-头部&#34;&gt;5.1 UDP 头部&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 0      7 8     15 16    23 24    31
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+--------+--------+--------+--------+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|     Source Port    |   Dest Port   |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+--------+--------+--------+--------+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|     Length         |   Checksum    |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+--------+--------+--------+--------+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|          data octets ...            |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+-------------------------------------+&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Source Port / Dest Port&lt;/strong&gt;：各 16 位，标识发送和接收进程。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Length&lt;/strong&gt;：UDP 头部 + 数据的总长度。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Checksum&lt;/strong&gt;：可选（IPv4 中），覆盖头部、数据和伪头部。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;52-udp-的特点与适用场景&#34;&gt;5.2 UDP 的特点与适用场景&lt;/h3&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;不可靠&lt;/td&gt;
					&lt;td&gt;不保证到达、不保证顺序、不重传&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;低开销&lt;/td&gt;
					&lt;td&gt;头部只有 8 字节&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;p&gt;&lt;strong&gt;适合用 UDP 的场景&lt;/strong&gt;：DNS 查询、视频直播、在线游戏、VoIP、NTP、QUIC 底层。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;避坑技巧&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UDP 没有流量控制，发送方太快会导致接收方丢包。实时音视频要做抖动缓冲（jitter buffer）和前向纠错（FEC）。&lt;/li&gt;
&lt;li&gt;UDP 报文超过 MTU 会被 IP 层分片，分片丢失会导致整个 UDP 报文作废。大数据包要在应用层分片。&lt;/li&gt;
&lt;li&gt;不要认为 UDP 一定比 TCP 快。在丢包率高的网络里，应用层自己实现可靠传输可能比 TCP 更复杂且效果更差。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;六tcp可靠传输的基石&#34;&gt;六、TCP：可靠传输的基石&lt;/h2&gt;
&lt;p&gt;TCP（Transmission Control Protocol）是互联网最常用的传输协议。它提供&lt;strong&gt;面向连接、可靠、按序、字节流&lt;/strong&gt;的服务。&lt;/p&gt;
&lt;h3 id=&#34;61-tcp-头部核心字段&#34;&gt;6.1 TCP 头部核心字段&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 0                   1                   2                   3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|          Source Port          |       Destination Port        |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|                        Sequence Number                        |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|                    Acknowledgment Number                      |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|  Data |           |U|A|P|R|S|F|                               |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;| Offset| Reserved  |R|C|S|S|Y|I|            Window             |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|       |           |G|K|H|T|N|N|                               |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|           Checksum            |         Urgent Pointer        |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;|                    Options                    |    Padding    |
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;关键字段：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Sequence Number（序号）&lt;/strong&gt;：标识本报文段发送的数据在字节流中的位置。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Acknowledgment Number（确认号）&lt;/strong&gt;：期望收到的下一个字节的序号。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ACK&lt;/strong&gt;：确认号有效。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SYN&lt;/strong&gt;：发起连接。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FIN&lt;/strong&gt;：结束连接。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RST&lt;/strong&gt;：重置连接，通常表示异常。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Window（窗口大小）&lt;/strong&gt;：接收方当前可用缓存大小，用于流量控制。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;62-三次握手建立连接&#34;&gt;6.2 三次握手：建立连接&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;sequenceDiagram
    participant C as 客户端
    participant S as 服务端

    C-&amp;gt;&amp;gt;S: SYN, seq=x
    Note over C,S: 客户端请求建立连接
    S-&amp;gt;&amp;gt;C: SYN, seq=y, ACK=x+1
    Note over C,S: 服务端同意，也请求建立反向连接
    C-&amp;gt;&amp;gt;S: ACK=y+1
    Note over C,S: 客户端确认，连接建立&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;为什么是三次？&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;两次握手无法确认客户端的接收能力，也不能防止历史重复连接请求造成资源浪费。&lt;/li&gt;
&lt;li&gt;三次是「双方都能发送和接收」的最小验证次数。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;关键状态&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;客户端：SYN_SENT → ESTABLISHED&lt;/li&gt;
&lt;li&gt;服务端：LISTEN → SYN_RCVD → ESTABLISHED&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;63-四次挥手关闭连接&#34;&gt;6.3 四次挥手：关闭连接&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;sequenceDiagram
    participant C as 客户端
    participant S as 服务端

    C-&amp;gt;&amp;gt;S: FIN, seq=u
    Note over C,S: 客户端没有数据要发了
    S-&amp;gt;&amp;gt;C: ACK=u+1
    Note over C,S: 服务端确认，但可能还有数据要发
    S-&amp;gt;&amp;gt;C: FIN, seq=w
    Note over C,S: 服务端也没有数据要发了
    C-&amp;gt;&amp;gt;S: ACK=w+1
    Note over C,S: 客户端确认&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;为什么一般是四次？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;TCP 是全双工的，两个方向要分别关闭。一方发完 FIN 只表示「我这方向没数据了」，另一方可能还有数据要发。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;关键状态与时间等待&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;主动关闭方最后进入 &lt;strong&gt;TIME_WAIT&lt;/strong&gt;，等待 2MSL（Maximum Segment Lifetime，通常 1-4 分钟）后才彻底关闭。&lt;/li&gt;
&lt;li&gt;TIME_WAIT 的作用：
&lt;ol&gt;
&lt;li&gt;确保最后一个 ACK 被对方收到，如果丢失可以重传。&lt;/li&gt;
&lt;li&gt;让网络中延迟的报文自然消失，避免影响下一个使用相同四元组的新连接。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;64-tcp-状态机&#34;&gt;6.4 TCP 状态机&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;stateDiagram-v2
    [*] --&amp;gt; CLOSED
    CLOSED --&amp;gt; SYN_SENT : 主动打开/send SYN
    CLOSED --&amp;gt; LISTEN : 被动打开
    SYN_SENT --&amp;gt; ESTABLISHED : 收到 SYN+ACK
    LISTEN --&amp;gt; SYN_RCVD : 收到 SYN
    SYN_RCVD --&amp;gt; ESTABLISHED : 收到 ACK
    ESTABLISHED --&amp;gt; FIN_WAIT_1 : 主动关闭/send FIN
    ESTABLISHED --&amp;gt; CLOSE_WAIT : 收到 FIN
    FIN_WAIT_1 --&amp;gt; FIN_WAIT_2 : 收到 ACK
    FIN_WAIT_1 --&amp;gt; TIME_WAIT : 收到 FIN+ACK
    FIN_WAIT_2 --&amp;gt; TIME_WAIT : 收到 FIN
    CLOSE_WAIT --&amp;gt; LAST_ACK : 发送 FIN
    LAST_ACK --&amp;gt; CLOSED : 收到 ACK
    TIME_WAIT --&amp;gt; CLOSED : 2MSL 超时&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;65-可靠传输机制&#34;&gt;6.5 可靠传输机制&lt;/h3&gt;
&lt;p&gt;TCP 通过以下机制保证可靠性：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    A[序号与确认机制] --&amp;gt; B[超时重传]
    C[滑动窗口] --&amp;gt; D[流量控制]
    E[拥塞窗口] --&amp;gt; F[拥塞控制]
    B --&amp;gt; G[可靠传输]
    D --&amp;gt; G
    F --&amp;gt; G&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;序号与确认&lt;/strong&gt;：每发一个字节都有序号，接收方用 ACK 确认连续收到的最大序号。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;超时重传&lt;/strong&gt;：发送方启动定时器，超时未收到 ACK 就重传。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;滑动窗口&lt;/strong&gt;：允许发送方在没收到 ACK 的情况下连续发送多个段，提高吞吐量。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;流量控制&lt;/strong&gt;：接收方通过 Window 字段告诉发送方自己还能接收多少数据，防止接收方缓存溢出。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;拥塞控制&lt;/strong&gt;：发送方根据网络拥塞程度调整发送速率，主要算法包括慢启动、拥塞避免、快重传、快恢复。&lt;/p&gt;
&lt;h3 id=&#34;66-拥塞控制四个阶段&#34;&gt;6.6 拥塞控制四个阶段&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TB
    A[慢启动&amp;lt;br/&amp;gt;cwnd 指数增长] --&amp;gt;|&amp;#34;cwnd &amp;gt;= ssthresh&amp;#34;| B[拥塞避免&amp;lt;br/&amp;gt;cwnd 线性增长]
    B --&amp;gt;|&amp;#34;收到 3 个重复 ACK&amp;#34;| C[快重传&amp;lt;br/&amp;gt;立即重传]
    C --&amp;gt; D[快恢复&amp;lt;br/&amp;gt;cwnd=ssthresh]
    D --&amp;gt; B
    B --&amp;gt;|&amp;#34;超时&amp;#34;| E[超时重传&amp;lt;br/&amp;gt;cwnd=1]
    E --&amp;gt; A&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;慢启动（Slow Start）&lt;/strong&gt;：初始窗口小，每收到一个 ACK 窗口近似翻倍，直到达到慢启动阈值（ssthresh）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;拥塞避免（Congestion Avoidance）&lt;/strong&gt;：超过阈值后，窗口线性增长。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;快重传（Fast Retransmit）&lt;/strong&gt;：收到 3 个重复 ACK 就立刻重传，不等超时。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;快恢复（Fast Recovery）&lt;/strong&gt;：快重传后不把窗口降到 1，而是降到 ssthresh，再线性增长。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;67-nagle-算法与延迟-ack&#34;&gt;6.7 Nagle 算法与延迟 ACK&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Nagle 算法&lt;/strong&gt;：减少小报文数量。如果上一次发送的数据还没被确认，且当前数据量小于 MSS，就把小数据攒起来一起发。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;延迟 ACK&lt;/strong&gt;：接收方不立即对每个收到的段发 ACK，而是等 40ms 左右，看是否有数据要一起回，减少 ACK 数量。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;避坑技巧&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Nagle + 延迟 ACK 会造成明显延迟&lt;/strong&gt;：发送方等小 ACK，接收方等大数据一起回，形成「写 - 等 - 写 - 等」的 ping-pong 效应。&lt;/li&gt;
&lt;li&gt;交互式应用（如游戏、SSH、RPC）通常要关闭 Nagle：&lt;code&gt;setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &amp;amp;on, sizeof(on))&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;批量传输场景（文件下载）可以保留 Nagle，减少小包数量。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;七dns-与-dhcp网络配置的基础设施&#34;&gt;七、DNS 与 DHCP：网络配置的基础设施&lt;/h2&gt;
&lt;h3 id=&#34;71-dns域名--ip&#34;&gt;7.1 DNS：域名 → IP&lt;/h3&gt;
&lt;p&gt;DNS（Domain Name System）是互联网的「电话簿」，把人类可读的域名解析成 IP 地址。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    A[客户端] --&amp;gt;|&amp;#34;查询 example.com&amp;#34;| B[本地 DNS 缓存]
    B --&amp;gt;|&amp;#34;未命中&amp;#34;| C[递归 DNS 服务器]
    C --&amp;gt;|&amp;#34;迭代查询&amp;#34;| D[根 DNS 服务器]
    D --&amp;gt; E[.com 顶级域服务器]
    E --&amp;gt; F[example.com 权威服务器]
    F --&amp;gt;|&amp;#34;返回 IP&amp;#34;| C
    C --&amp;gt;|&amp;#34;返回 IP&amp;#34;| A&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;DNS 记录类型&lt;/strong&gt;：&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;域名 → IPv4 地址&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;AAAA&lt;/td&gt;
					&lt;td&gt;域名 → IPv6 地址&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;CNAME&lt;/td&gt;
					&lt;td&gt;域名别名&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;MX&lt;/td&gt;
					&lt;td&gt;邮件交换服务器&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;NS&lt;/td&gt;
					&lt;td&gt;权威 DNS 服务器&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;TXT&lt;/td&gt;
					&lt;td&gt;文本记录，常用于验证和 SPF&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;避坑技巧&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DNS 有缓存，修改记录后全球生效可能要几分钟到 48 小时（受 TTL 控制）。&lt;/li&gt;
&lt;li&gt;注意 DNS 解析失败和连接超时的区别：先 &lt;code&gt;nslookup&lt;/code&gt;/&lt;code&gt;dig&lt;/code&gt; 确认域名能否解析，再 ping/telnet 确认网络层是否通。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gethostbyname&lt;/code&gt; 不是线程安全的，现代程序应使用 &lt;code&gt;getaddrinfo&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;72-dhcp自动获取网络配置&#34;&gt;7.2 DHCP：自动获取网络配置&lt;/h3&gt;
&lt;p&gt;DHCP（Dynamic Host Configuration Protocol）让主机自动获取 IP 地址、子网掩码、网关、DNS 服务器。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;sequenceDiagram
    participant H as 主机
    participant D as DHCP 服务器

    H-&amp;gt;&amp;gt;D: DHCP Discover（广播）
    D-&amp;gt;&amp;gt;H: DHCP Offer
    H-&amp;gt;&amp;gt;D: DHCP Request
    D-&amp;gt;&amp;gt;H: DHCP ACK&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;八unix-网络编程核心socket-api&#34;&gt;八、Unix 网络编程核心：Socket API&lt;/h2&gt;
&lt;p&gt;Socket 是 Unix 系统提供的网络编程接口，屏蔽了底层协议细节，让程序像读写文件一样通信。&lt;/p&gt;
&lt;h3 id=&#34;81-tcp-服务端典型调用流程&#34;&gt;8.1 TCP 服务端典型调用流程&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TB
    A[socket] --&amp;gt; B[bind]
    B --&amp;gt; C[listen]
    C --&amp;gt; D[accept]
    D --&amp;gt; E[read/write]
    E --&amp;gt; F[close]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;82-tcp-客户端典型调用流程&#34;&gt;8.2 TCP 客户端典型调用流程&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TB
    A[socket] --&amp;gt; B[connect]
    B --&amp;gt; C[read/write]
    C --&amp;gt; D[close]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;83-核心-api-说明&#34;&gt;8.3 核心 API 说明&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;API&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;socket()&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;创建套接字，指定协议族（IPv4/IPv6）和类型（流式/数据报）&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;bind()&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;把套接字绑定到本地地址和端口&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;listen()&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;把套接字置为监听状态，指定全连接队列长度&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;accept()&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;从全连接队列取出一个已完成握手的连接&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;connect()&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;客户端发起连接&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;read()/write()&lt;/code&gt; 或 &lt;code&gt;recv()/send()&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;收发数据&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;close()&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;关闭连接&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;shutdown()&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;半关闭：只关闭读或写&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;84-最简-tcp-服务端示例&#34;&gt;8.4 最简 TCP 服务端示例&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;string.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;arpa/inet.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define PORT 8080
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define BACKLOG 128
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; listen_fd &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;socket&lt;/span&gt;(AF_INET, SOCK_STREAM, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (listen_fd &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;perror&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;socket&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;exit&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; reuse &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;setsockopt&lt;/span&gt;(listen_fd, SOL_SOCKET, SO_REUSEADDR, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;reuse, &lt;span style=&#34;color:#66d9ef&#34;&gt;sizeof&lt;/span&gt;(reuse));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; sockaddr_in addr;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;memset&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;addr, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;sizeof&lt;/span&gt;(addr));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    addr.sin_family &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; AF_INET;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    addr.sin_addr.s_addr &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; INADDR_ANY;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    addr.sin_port &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;htons&lt;/span&gt;(PORT);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;bind&lt;/span&gt;(listen_fd, (&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; sockaddr &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;addr, &lt;span style=&#34;color:#66d9ef&#34;&gt;sizeof&lt;/span&gt;(addr)) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;perror&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;bind&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;exit&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;listen&lt;/span&gt;(listen_fd, BACKLOG) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;perror&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;listen&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;exit&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Server listening on port %d&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;, PORT);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; (&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; sockaddr_in client_addr;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;socklen_t&lt;/span&gt; len &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;sizeof&lt;/span&gt;(client_addr);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; conn_fd &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;accept&lt;/span&gt;(listen_fd, (&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; sockaddr &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;client_addr, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;len);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (conn_fd &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;perror&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;accept&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;continue&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; buf[&lt;span style=&#34;color:#ae81ff&#34;&gt;1024&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;ssize_t&lt;/span&gt; n &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;read&lt;/span&gt;(conn_fd, buf, &lt;span style=&#34;color:#66d9ef&#34;&gt;sizeof&lt;/span&gt;(buf) &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (n &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            buf[n] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;\0&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Received: %s&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;, buf);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;write&lt;/span&gt;(conn_fd, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;OK&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;close&lt;/span&gt;(conn_fd);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;close&lt;/span&gt;(listen_fd);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;85-最简-tcp-客户端示例&#34;&gt;8.5 最简 TCP 客户端示例&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;string.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;arpa/inet.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define SERVER &amp;#34;127.0.0.1&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#define PORT 8080
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; fd &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;socket&lt;/span&gt;(AF_INET, SOCK_STREAM, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (fd &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;perror&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;socket&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;exit&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; sockaddr_in addr;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;memset&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;addr, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;sizeof&lt;/span&gt;(addr));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    addr.sin_family &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; AF_INET;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    addr.sin_port &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;htons&lt;/span&gt;(PORT);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;inet_pton&lt;/span&gt;(AF_INET, SERVER, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;addr.sin_addr);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;connect&lt;/span&gt;(fd, (&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; sockaddr &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;addr, &lt;span style=&#34;color:#66d9ef&#34;&gt;sizeof&lt;/span&gt;(addr)) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;perror&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;connect&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;exit&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;write&lt;/span&gt;(fd, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hello&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; buf[&lt;span style=&#34;color:#ae81ff&#34;&gt;1024&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;ssize_t&lt;/span&gt; n &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;read&lt;/span&gt;(fd, buf, &lt;span style=&#34;color:#66d9ef&#34;&gt;sizeof&lt;/span&gt;(buf) &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (n &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        buf[n] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;\0&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Server reply: %s&amp;#34;&lt;/span&gt;, buf);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;close&lt;/span&gt;(fd);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;九unix-网络编程常见陷阱与避坑技巧&#34;&gt;九、Unix 网络编程常见陷阱与避坑技巧&lt;/h2&gt;
&lt;h3 id=&#34;91-必须设置-so_reuseaddr&#34;&gt;9.1 必须设置 SO_REUSEADDR&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; reuse &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;setsockopt&lt;/span&gt;(listen_fd, SOL_SOCKET, SO_REUSEADDR, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;reuse, &lt;span style=&#34;color:#66d9ef&#34;&gt;sizeof&lt;/span&gt;(reuse));&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;原因&lt;/strong&gt;：服务端主动关闭连接后会进入 TIME_WAIT，该连接的本地端口短时间内不能复用。如果不设置 SO_REUSEADDR，重启服务时可能报 &lt;code&gt;Address already in use&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：SO_REUSEADDR 允许复用 TIME_WAIT 的端口，但不会允许两个进程同时绑定到完全相同的 &lt;code&gt;IP:端口&lt;/code&gt;（Linux 上 SO_REUSEPORT 才能做到）。&lt;/p&gt;
&lt;h3 id=&#34;92-正确处理-sigpipe&#34;&gt;9.2 正确处理 SIGPIPE&lt;/h3&gt;
&lt;p&gt;向一个已经收到 RST 的 socket 写数据会触发 &lt;code&gt;SIGPIPE&lt;/code&gt; 信号，默认行为是终止进程。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;signal&lt;/span&gt;(SIGPIPE, SIG_IGN);  &lt;span style=&#34;color:#75715e&#34;&gt;// 忽略信号
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;更优雅的做法是在写之前检查连接状态，或者使用 &lt;code&gt;MSG_NOSIGNAL&lt;/code&gt; 标志：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;send&lt;/span&gt;(fd, buf, len, MSG_NOSIGNAL);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;93-处理部分读写&#34;&gt;9.3 处理部分读写&lt;/h3&gt;
&lt;p&gt;TCP 是字节流，&lt;code&gt;read&lt;/code&gt; 和 &lt;code&gt;write&lt;/code&gt; 不保证一次读完或写完。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 可靠的写：循环写直到写完
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;ssize_t&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;write_all&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; fd, &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;buf, &lt;span style=&#34;color:#66d9ef&#34;&gt;size_t&lt;/span&gt; len) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;p &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; buf;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;size_t&lt;/span&gt; remaining &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; len;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; (remaining &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;ssize_t&lt;/span&gt; n &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;write&lt;/span&gt;(fd, p, remaining);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (n &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (errno &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; EINTR) &lt;span style=&#34;color:#66d9ef&#34;&gt;continue&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        p &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; n;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        remaining &lt;span style=&#34;color:#f92672&#34;&gt;-=&lt;/span&gt; n;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; len;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;94-处理-eintr&#34;&gt;9.4 处理 EINTR&lt;/h3&gt;
&lt;p&gt;慢系统调用（如 &lt;code&gt;accept&lt;/code&gt;、&lt;code&gt;read&lt;/code&gt;、&lt;code&gt;write&lt;/code&gt;）被信号中断后会返回 -1 并设置 &lt;code&gt;errno = EINTR&lt;/code&gt;。 robust 的程序应该重试：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;while&lt;/span&gt; ((n &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;read&lt;/span&gt;(fd, buf, len)) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; errno &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; EINTR)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;95-不要用-strlen-计算二进制数据长度&#34;&gt;9.5 不要用 strlen 计算二进制数据长度&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;send(fd, buf, strlen(buf), 0)&lt;/code&gt; 只适合文本。二进制数据里可能有 &lt;code&gt;\0&lt;/code&gt;，要用实际长度。&lt;/p&gt;
&lt;h3 id=&#34;96-使用-getaddrinfo-替代-gethostbyname&#34;&gt;9.6 使用 getaddrinfo 替代 gethostbyname&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;gethostbyname&lt;/code&gt; 只支持 IPv4，不是线程安全的，已经被废弃。现代程序应使用 &lt;code&gt;getaddrinfo&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; addrinfo hints, &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;res;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;memset&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;hints, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;sizeof&lt;/span&gt;(hints));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;hints.ai_family &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; AF_UNSPEC;      &lt;span style=&#34;color:#75715e&#34;&gt;// 支持 IPv4 和 IPv6
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;hints.ai_socktype &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; SOCK_STREAM;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; err &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getaddrinfo&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;example.com&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;80&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;hints, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;res);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (err &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;fprintf&lt;/span&gt;(stderr, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;getaddrinfo: %s&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;gai_strerror&lt;/span&gt;(err));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;exit&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; fd &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;socket&lt;/span&gt;(res&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;ai_family, res&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;ai_socktype, res&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;ai_protocol);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;connect&lt;/span&gt;(fd, res&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;ai_addr, res&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;ai_addrlen);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;freeaddrinfo&lt;/span&gt;(res);  &lt;span style=&#34;color:#75715e&#34;&gt;// 记得释放
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;97-区分-close-与-shutdown&#34;&gt;9.7 区分 close 与 shutdown&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;close(fd)&lt;/code&gt;：关闭文件描述符，引用计数减到 0 时释放资源，双向关闭。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;shutdown(fd, SHUT_WR)&lt;/code&gt;：只关闭写方向，读仍然可以接收数据，常用于通知对端「我发完了」。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;98-阻塞-vs-非阻塞-io&#34;&gt;9.8 阻塞 vs 非阻塞 IO&lt;/h3&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;调用没完成就挂起&lt;/td&gt;
					&lt;td&gt;简单程序、每个连接一个线程/进程&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;非阻塞&lt;/td&gt;
					&lt;td&gt;调用立即返回，没数据返回 EAGAIN/EWOULDBLOCK&lt;/td&gt;
					&lt;td&gt;高并发、IO 多路复用&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;99-io-多路复用&#34;&gt;9.9 IO 多路复用&lt;/h3&gt;
&lt;p&gt;单线程服务大量连接时，要用 IO 多路复用同时监视多个 fd 的就绪状态。&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    A[主线程] --&amp;gt; B[select/poll/epoll]
    B --&amp;gt;|&amp;#34;哪些 fd 可读/可写&amp;#34;| C[处理可读 fd]
    B --&amp;gt; D[处理可写 fd]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&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;select&lt;/td&gt;
					&lt;td&gt;有 fd 数量限制（通常 1024），每次调用要遍历全部 fd&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;poll&lt;/td&gt;
					&lt;td&gt;用数组描述 fd，没有数量硬限制，但仍需遍历&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;epoll（Linux）&lt;/td&gt;
					&lt;td&gt;事件驱动，只关注活跃的 fd，支持边缘触发和水平触发&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;kqueue（BSD/macOS）&lt;/td&gt;
					&lt;td&gt;类似 epoll，事件驱动&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;epoll 水平触发（LT）vs 边缘触发（ET）&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LT：只要 fd 还有数据可读，epoll 就会一直通知。&lt;/li&gt;
&lt;li&gt;ET：只有 fd 状态变化时通知一次，需要一次性把数据读完，通常配合非阻塞 IO。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;十典型-unix-网络障碍问题与排查思路&#34;&gt;十、典型 Unix 网络障碍问题与排查思路&lt;/h2&gt;
&lt;h3 id=&#34;101-排查流程总览&#34;&gt;10.1 排查流程总览&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart TD
    A[网络问题] --&amp;gt; B[确认是 DNS/路由/端口/应用哪一层]
    B --&amp;gt; C{能解析域名吗?}
    C --&amp;gt;|否| D[检查 DNS / hosts / 防火墙]
    C --&amp;gt;|是| E{能 ping 通 IP 吗?}
    E --&amp;gt;|否| F[检查路由 / ACL / 安全组]
    E --&amp;gt;|是| G{端口通吗?}
    G --&amp;gt;|否| H[检查服务是否监听 / 防火墙 / 安全组]
    G --&amp;gt;|是| I[检查应用日志 / 抓包 / 连接状态]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;102-connection-refused&#34;&gt;10.2 Connection refused&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;原因&lt;/strong&gt;：目标 IP 可达，但目标端口没有进程在监听，或者防火墙明确拒绝。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;排查&lt;/strong&gt;：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 服务端检查是否在监听&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ss -tlnp | grep &lt;span style=&#34;color:#ae81ff&#34;&gt;8080&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;netstat -tlnp | grep &lt;span style=&#34;color:#ae81ff&#34;&gt;8080&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 客户端测试端口是否开放&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;telnet server_ip &lt;span style=&#34;color:#ae81ff&#34;&gt;8080&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nc -vz server_ip &lt;span style=&#34;color:#ae81ff&#34;&gt;8080&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;103-connection-timed-out&#34;&gt;10.3 Connection timed out&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;原因&lt;/strong&gt;：报文到达目的地过程中被丢弃，没有收到任何 RST 或响应，常见于防火墙静默丢弃、路由不可达、NAT 映射问题。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;排查&lt;/strong&gt;：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 看路径到哪里断了&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;traceroute server_ip
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mtr server_ip
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 抓包看 SYN 有没有出去、有没有回来&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tcpdump -i any port &lt;span style=&#34;color:#ae81ff&#34;&gt;8080&lt;/span&gt; -nn&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;h3 id=&#34;104-too-many-time_wait--端口耗尽&#34;&gt;10.4 Too many TIME_WAIT / 端口耗尽&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;现象&lt;/strong&gt;：高并发短连接场景下，客户端连接失败，报错 &lt;code&gt;Cannot assign requested address&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;原因&lt;/strong&gt;：大量主动关闭的连接堆积在 TIME_WAIT，占用了本地端口。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决思路&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;尽量使用长连接 / 连接池。&lt;/li&gt;
&lt;li&gt;服务端设置 &lt;code&gt;SO_REUSEADDR&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;Linux 可调整 &lt;code&gt;net.ipv4.ip_local_port_range&lt;/code&gt; 扩大临时端口范围。&lt;/li&gt;
&lt;li&gt;开启 &lt;code&gt;net.ipv4.tcp_tw_reuse&lt;/code&gt;（谨慎，仅对客户端出站连接有效，不要开 &lt;code&gt;tcp_tw_recycle&lt;/code&gt;，已在内核 4.12 后移除）。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;105-close_wait-堆积&#34;&gt;10.5 CLOSE_WAIT 堆积&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;现象&lt;/strong&gt;：服务端 &lt;code&gt;ss -tan | grep CLOSE_WAIT&lt;/code&gt; 看到很多连接。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;原因&lt;/strong&gt;：对端已经发了 FIN，但本端应用没有调用 &lt;code&gt;close()&lt;/code&gt;，通常是因为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;应用逻辑忘记关闭 socket。&lt;/li&gt;
&lt;li&gt;应用在处理完数据前阻塞在某处，无法执行 close。&lt;/li&gt;
&lt;li&gt;异常分支没有释放连接资源。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;解决&lt;/strong&gt;：检查代码里所有异常路径是否都调用了 &lt;code&gt;close&lt;/code&gt;，确保每个 &lt;code&gt;accept&lt;/code&gt; 出来的 fd 都有对应的关闭点。&lt;/p&gt;
&lt;h3 id=&#34;106-syn-flood--半连接队列溢出&#34;&gt;10.6 SYN Flood / 半连接队列溢出&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;现象&lt;/strong&gt;：服务偶尔出现连接建立慢或大量 &lt;code&gt;SYN_SENT&lt;/code&gt;/&lt;code&gt;SYN_RECV&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;原理&lt;/strong&gt;：Linux 内核有两个队列：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;半连接队列（syn queue）&lt;/strong&gt;：存放收到 SYN 但还没完成三次握手的连接。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;全连接队列（accept queue）&lt;/strong&gt;：存放已完成三次握手但还没被 &lt;code&gt;accept&lt;/code&gt; 取走的连接。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    A[客户端 SYN] --&amp;gt;|&amp;#34;进入半连接队列&amp;#34;| B[SYN_RCVD]
    B --&amp;gt;|&amp;#34;收到 ACK&amp;#34;| C[ESTABLISHED]
    C --&amp;gt;|&amp;#34;进入全连接队列&amp;#34;| D[等待 accept]
    D --&amp;gt;|&amp;#34;accept 取走&amp;#34;| E[交给业务处理]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;排查&lt;/strong&gt;：&lt;/p&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ss -s          &lt;span style=&#34;color:#75715e&#34;&gt;# 查看连接统计&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ss -lnt        &lt;span style=&#34;color:#75715e&#34;&gt;# 看全连接队列长度和溢出次数&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;netstat -s | grep overflow&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;p&gt;&lt;strong&gt;解决&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;调大 &lt;code&gt;net.ipv4.tcp_max_syn_backlog&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;开启 SYN Cookies：&lt;code&gt;net.ipv4.tcp_syncookies = 1&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;增大 &lt;code&gt;listen(fd, backlog)&lt;/code&gt; 的 backlog，同时配合 &lt;code&gt;somaxconn&lt;/code&gt; 调整。&lt;/li&gt;
&lt;li&gt;提升应用 &lt;code&gt;accept&lt;/code&gt; 速度。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;107-高并发下-accept-慢或全连接队列溢出&#34;&gt;10.7 高并发下 accept 慢或全连接队列溢出&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;现象&lt;/strong&gt;：连接完成三次握手，但客户端一直等待服务端响应。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;原因&lt;/strong&gt;：&lt;code&gt;accept&lt;/code&gt; 处理太慢，全连接队列满了，新的完成连接被丢弃。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用多线程/多进程分担 accept。&lt;/li&gt;
&lt;li&gt;使用 IO 多路复用 + 事件驱动架构。&lt;/li&gt;
&lt;li&gt;调整 &lt;code&gt;net.core.somaxconn&lt;/code&gt; 和 &lt;code&gt;listen()&lt;/code&gt; 的 backlog。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;108-mtumss-导致的大包不通&#34;&gt;10.8 MTU/MSS 导致的大包不通&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;现象&lt;/strong&gt;：小数据包能通，大数据包不通；或某些网站/服务能打开，某些打不开。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;原因&lt;/strong&gt;：路径中某段链路 MTU 较小，大包被丢弃，且中间设备不发送 ICMP &amp;ldquo;Fragmentation Needed&amp;rdquo;，导致无法自动降包大小。这就是著名的 &lt;strong&gt;PMTUD（Path MTU Discovery）黑洞&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;设置 &lt;code&gt;net.ipv4.tcp_mtu_probing = 1&lt;/code&gt; 启用 TCP MTU 探测。&lt;/li&gt;
&lt;li&gt;在 VPN/隧道两端统一调低 MTU/MSS。&lt;/li&gt;
&lt;li&gt;中间网络设备不要丢弃 ICMP &amp;ldquo;Fragmentation Needed&amp;rdquo;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;109-应用层协议粘包拆包&#34;&gt;10.9 应用层协议粘包/拆包&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;现象&lt;/strong&gt;：TCP 客户端发了两条消息，服务端一次 read 读到了两条消息的内容。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;原因&lt;/strong&gt;：TCP 是字节流，没有消息边界。应用层需要自己定义消息边界。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;常见解决方案&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;固定长度&lt;/strong&gt;：每个消息固定 N 字节。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;分隔符&lt;/strong&gt;：如 &lt;code&gt;\n&lt;/code&gt;、自定义分隔符。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;长度前缀&lt;/strong&gt;：消息头 4 字节表示消息体长度。&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 长度前缀示例：先读 4 字节长度，再读对应长度的 body
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;uint32_t&lt;/span&gt; len;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;read_all&lt;/span&gt;(fd, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;len, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;len &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ntohl&lt;/span&gt;(len);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;read_all&lt;/span&gt;(fd, body, len);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;十一学习路线与推荐资源&#34;&gt;十一、学习路线与推荐资源&lt;/h2&gt;
&lt;h3 id=&#34;111-学习顺序建议&#34;&gt;11.1 学习顺序建议&lt;/h3&gt;
&lt;div class=&#34;code-block&#34;&gt;
    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;
      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;
    &lt;/button&gt;
    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-mermaid&#34; data-lang=&#34;mermaid&#34;&gt;flowchart LR
    A[网络分层模型] --&amp;gt; B[IP/子网/路由]
    B --&amp;gt; C[ARP/ICMP]
    C --&amp;gt; D[TCP 握手挥手与状态机]
    D --&amp;gt; E[滑动窗口与拥塞控制]
    E --&amp;gt; F[Socket API 编程]
    F --&amp;gt; G[IO 多路复用]
    G --&amp;gt; H[Wireshark 抓包分析]
    H --&amp;gt; I[线上问题排查]&lt;/code&gt;&lt;/pre&gt;
  &lt;/div&gt;&lt;h3 id=&#34;112-推荐实践&#34;&gt;11.2 推荐实践&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;用 Wireshark 抓一次完整的三次握手和四次挥手&lt;/strong&gt;，亲眼看看每个字段的值。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;写一个 echo 服务器&lt;/strong&gt;，先用阻塞 IO，再用 select/epoll 改写。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;故意制造问题&lt;/strong&gt;：把客户端改成快速创建大量短连接，观察 TIME_WAIT；把服务端 accept 故意睡几秒，观察全连接队列溢出。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用 &lt;code&gt;ss&lt;/code&gt;、&lt;code&gt;tcpdump&lt;/code&gt;、&lt;code&gt;traceroute&lt;/code&gt;、&lt;code&gt;nc&lt;/code&gt;、&lt;code&gt;iperf&lt;/code&gt; 这些工具做实验&lt;/strong&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;113-推荐参考书&#34;&gt;11.3 推荐参考书&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;《TCP/IP 详解 卷1：协议》（W. Richard Stevens）——协议细节最权威。&lt;/li&gt;
&lt;li&gt;《Unix 网络编程 卷1：套接字联网 API》（W. Richard Stevens）——Socket 编程圣经。&lt;/li&gt;
&lt;li&gt;《Wireshark 网络分析就这么简单》——抓包实战。&lt;/li&gt;
&lt;li&gt;《Linux 高性能服务器编程》（游双）——中文入门友好。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;十二总结&#34;&gt;十二、总结&lt;/h2&gt;
&lt;p&gt;TCP/IP 协议栈并不神秘，它的核心思想就是&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;li&gt;应用层负责「这些数据代表什么业务含义」。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Unix 网络编程的核心是理解 Socket API 的调用顺序、IO 模型、以及 TCP 连接的生命周期。写出稳定的网络程序，不在于记住所有参数，而在于理解：&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;希望这份总结能帮你把《TCP/IP 详解》里的知识点串成一张网，少踩一些网络编程里的经典大坑。&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>
