应用层相关协议
本文系统梳理计算机网络的核心原理,从应用层的数据交换格式与端口号,到传输层 TCP 的十大核心机制与状态机,再到网络层 IP 协议、路由选择、差错检测以及 DNS 解析。理解这些内容,是掌握 JavaEE 网络编程与排查线上网络问题的重要铺垫。
目录
- 应用层:请求/响应格式(XML / JSON / Protobuf)
- 端口号
- 传输层(TCP 核心机制 / TCP 状态 / UDP)
- 网络层(IP 协议 / IP 地址 / 路由选择 / CRC 校验)
- DNS(应用层重要协议)
请求与响应数据格式
请求中通常带有请求头,例如客户端的位置、需求等信息。
响应中也会携带相应的状态与数据信息。
常见的数据交换格式如下。
XML
使用成对的标签来表示数据。
注意:HTML 并不是 XML 的子集(HTML 语法宽松,标签可不闭合);只有 XHTML 才是 XML 的一种应用,二者不要混淆。
下面是一个 XML 示例。

XML 的可扩展性和可读性都很好。
缺点是传输效率较差,因为我们引入了大量标签信息来承载实际内容。
这种格式在早期较为常用,现在基本已被抛弃。
JSON
json
{
"userid": 1234,
"position": "12E45N"
}
相比 XML,JSON 的标签体积大约减少了一半。
Google Protobuf
目前比较流行,但普及程度仍不如 JSON。
优点是采用二进制编码,压缩率高。
缺点是可读性差,毕竟本质上是二进制文件。
除了自定义协议之外,业界也有成熟的标准协议,例如 HTTP。
端口号

一个进程可以绑定多个端口号(本质上是 socket 绑定了端口号)。
一个端口号通常只能被一个 socket 绑定(特殊情况如 SO_REUSEADDR 等例外)。
传输层
UDP 单个数据报最大只能传输 64KB,因此我们经常需要手动分包、多次发送。
UDP 的不可靠主要体现在:它只负责把数据发出去,而不管对方是否真正收到。
UDP 主要适用于以下场景:
- 本身不容易丢包(既然 UDP 不关心是否丢包,那么在该场景下不丢包即可满足需求)。
- 对传输效率要求高。
校验和:类似于 MD5 检测。一般认为,两份数据校验和相同则大概率一致,校验和不同则一定存在问题。
最常见的校验算法是 CRC。
TCP 没有 UDP 这种 64KB 的上限,它依靠流式传输和分段机制,理论上可以传输任意大的数据。
TCP 核心机制

| 标志位 | 全称 | 核心作用 | 典型应用场景 |
|---|---|---|---|
| URG | Urgent | 标识紧急数据,要求优先处理 | 中断通信(如 Ctrl+C)、带外数据 |
| ACK | Acknowledgment | 确认号字段有效,用于确认数据 | 所有数据传输和连接管理阶段 |
| PSH | Push | 要求接收方立即将数据交付给应用层 | 交互式应用(如 Telnet)、实时数据 |
| RST | Reset | 重置连接,用于异常情况 | 连接拒绝、异常终止、SYN 攻击防护 |
| SYN | Synchronize | 同步序列号,用于建立连接 | TCP 三次握手 |
| FIN | Finish | 发送方数据发送完毕,请求关闭连接 | TCP 四次挥手 |
TCP 是面向字节流、全双工、可靠的、有连接的传输协议。
可靠传输
可靠传输并不意味着数据必然被送达,而是说:对方会给出应答,发送方由此知道数据是否送达。收到了应答就结束,没收到就再做处理。
1. 确认应答
确认应答是 TCP 实现可靠传输的核心机制。
但这种方式会出现"后发先至"的问题(解决方案是依靠编号来解决)。
由于 TCP 是面向字节流的,因此编号直接对字节进行编号(通过序号和确认序号实现)。
2. 超时重传
发送方等待一段时间以接收对方的 ACK,如果等不到就重发。这里存在一个问题:如果对方的 ACK 在回传给发送方的过程中丢包了,发送方同样会触发重传。
但重复重传显然有问题。
如何解决?我们先将数据放入缓冲区,应用程序读取时如果发现该数据的序号已被包含,则直接丢弃、不再向上交付。
如果一直无法连通,重传的间隔时间会不断变长,最终发送方会直接放弃连接。
超时重传与确认应答,是 TCP 实现可靠传输最核心的两大机制。
3. 连接管理(三次握手与四次挥手)
建立连接:三次握手(handshake)。
网络中的握手,就是发送一个不含实际数据的数据包。
第一次:携带 SYN(置 1 即表示同步报文),表示"我已保存了你的信息"。
然后对方返回一个 ACK,同时对方也发送一个同步报文,表示"你也保存了我的信息"(第二次)。
你再发送一个 ACK(第三次)。
这相当于"投石问路",先试探一下能否成功建立连接。
在此过程中,双方都确认了对方能够发送和接收信号。
三次握手的目的不是保证可靠传输,而是验证双方是否具备进行可靠传输的条件。
同时,它还能确定从哪个序号开始传输。因为有可能你明明已经重新连接,但上一次连接中丢失的报文现在才送达,对端通过序号差距很大即可直接拒绝。
断开连接:四次挥手。
java
if(!scanner.hasNext()){
System.out.printf("[%s:%d] 客户端下线\n",socket.getInetAddress(),socket.getPort());
break;
}
在我们的简单逻辑中,四次挥手可以合并为三次;但如果逻辑比较复杂,则必须拆分为四次。
具体解释:客户端发送 FIN 给服务器,表明"我没有数据要发了"。
服务器收到后回复 ACK,然后开始准备断开连接,之后再发送 FIN(这一步可能合并,也可能分两步)。
最后客户端发送 ACK 表示确认接收。
4. 滑动窗口

在普通的确认应答模式下,我们花费了大量时间在等待 ACK 上。

因此我们可以批量发送数据,从而避免频繁等待 ACK。

这就是滑动窗口,本质上属于"亡羊补牢"------在效率已经存在损失的前提下,尽可能减少损失。
那么窗口内的丢包如何处理?
- ACK 丢失:不管它,因为后一个 ACK 能够覆盖前一个。
- 数据丢失:

为何要多次确认 1001?是为了防止这部分数据只是"卡住了",而非"丢了"。
如果你发送数据的速度很慢,就不会构成滑动窗口。
5. 流量控制
流量控制用于保证可靠性:如果发送速度过快,接收方可能处理不过来,导致接收方不得不丢弃新到的数据。
接收方维护一个接收缓冲区,当数据积累到一定程度、缓冲区满了,新数据就会被丢弃。
因此,流量控制就是根据接收方的处理能力,反向控制发送方的发送速率。
接收方再通过 ACK 把剩余窗口大小带回去。
如果剩余窗口变为 0,发送方会周期性地发送一个不含数据的探测包,询问对方当前还有多少剩余空间。
注意:以上都属于"可靠性"范畴,而非"安全性"。
6. 拥塞控制
拥塞控制与流量控制类似,都是对滑动窗口作出限制。
流量控制依据的是接收方的处理能力。
拥塞控制依据的是整条通信路径的处理能力。
(也就是说,因为数据传输要依赖多个路由器转发,若中间某个路由器处理速度慢,数据就会堆积在那里。)
基本思路是"试探":丢包了就减速,没丢包就加速。
即"面多加水,水多加面"。
具体做法是维护一个 int 变量来描述窗口大小。
实际发送窗口大小为:min(流量控制窗口, 拥塞窗口)。

最开始窗口很小,随后指数级增长。
当增长到超过某个设定阈值后,转为线性增长;一旦中途发生丢包,窗口就缩小。
7. 延时应答
延时应答的目的是在尽可能的情况下扩大窗口。
如果我们立即返回 ACK,应用层只处理了一点点数据,因此窗口较小。
如果我们不立即返回 ACK,应用层可能已处理了一部分数据,从而能通告更大的窗口。
8. 捎带应答
正常模式是一问一答。
我先询问,对方确认收到;对方再应答,我确认收到。
但配合延时应答,对方可以直接把"应答"和"确认收到"合并发送给我。
这也是四次挥手能够变成三次挥手的原因。
9. 面向字节流与粘包问题
这是"粘包问题"的来源之一。
先解释一下粘包:
假设我发了两个包,一个是 a,另一个是 b。
我希望对方先接收 a、再接收 b,但两个包都进入了缓冲区。
结果对方一次性全部读取,变成了 a+b。
下面是拆包:
也有可能是我发的是 a+b,但接收方读取较快,变成了先 a 后 b。
TCP 不关心你应用层的数据包是如何划分的,因为包与包之间没有明确的界限,必须在应用层自行处理。
10. 异常情况处理
1. 进程崩溃
无论以何种方式退出,操作系统都会自动进行清理和资源回收。
2. 主机正常关机
如果关机速度正常,四次挥手能够跑完。
若关机速度太快,四次挥手无法跑完:
- 服务器最后发出 FIN,你这边没有回应。
- 服务器开始重传。
- 最终服务端删除此前保留的你的相关信息。
- 一切恢复正常。
3. 主机掉电/关机
程序完全无法进行挥手操作。
-
接收方关机:
- 无法给发送方传 ACK。
- 发送方重传。
- 发送方一直收不到 ACK。
- 发送方放弃连接,发送复位报文(RST)。
-
发送方关机:
- 接收方傻眼了:发方是挂了,还是只是休息一会?
- 接收方会不时发一个空包(心跳包),即询问"你在不在",目的是触发对方的 ACK 回传。
- 如果发方已挂,接收方主动断开连接。
当然,我们一般会重写心跳包,因为 TCP 自带的心跳要几十毫秒才会断开。
4. 网线断开
这种情况与主机掉电关机类似。
TCP 状态
LISTEN
服务器监听状态,等待客户端连接。
ESTABLISHED
连接已成功建立,可以开始收发数据。
CLOSE_WAIT
一方收到 FIN 后即进入该状态,等待调用 close 方法;调用后发出 FIN,从而跳出该状态。
如果该状态长期存在,通常说明代码存在 Bug(未正确关闭连接)。
TIME_WAIT
主动断开连接的一方会进入该状态,作用是等待一段时间,以处理最后一个 ACK 丢包的特殊情况。
如果该状态很多,说明大多数连接是由服务器主动断开的。
TCP 完整状态机(11 种状态 + CLOSED)
#mermaid-svg-15LHEwEUwVvJS5o7{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-15LHEwEUwVvJS5o7 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-15LHEwEUwVvJS5o7 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-15LHEwEUwVvJS5o7 .error-icon{fill:#552222;}#mermaid-svg-15LHEwEUwVvJS5o7 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-15LHEwEUwVvJS5o7 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-15LHEwEUwVvJS5o7 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-15LHEwEUwVvJS5o7 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-15LHEwEUwVvJS5o7 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-15LHEwEUwVvJS5o7 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-15LHEwEUwVvJS5o7 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-15LHEwEUwVvJS5o7 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-15LHEwEUwVvJS5o7 .marker.cross{stroke:#333333;}#mermaid-svg-15LHEwEUwVvJS5o7 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-15LHEwEUwVvJS5o7 p{margin:0;}#mermaid-svg-15LHEwEUwVvJS5o7 defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-15LHEwEUwVvJS5o7 g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-15LHEwEUwVvJS5o7 g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-15LHEwEUwVvJS5o7 g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-15LHEwEUwVvJS5o7 g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-15LHEwEUwVvJS5o7 g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-15LHEwEUwVvJS5o7 .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-15LHEwEUwVvJS5o7 .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-15LHEwEUwVvJS5o7 .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-15LHEwEUwVvJS5o7 .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-15LHEwEUwVvJS5o7 .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-15LHEwEUwVvJS5o7 .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-15LHEwEUwVvJS5o7 .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-15LHEwEUwVvJS5o7 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-15LHEwEUwVvJS5o7 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-15LHEwEUwVvJS5o7 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-15LHEwEUwVvJS5o7 .edgeLabel .label text{fill:#333;}#mermaid-svg-15LHEwEUwVvJS5o7 .label div .edgeLabel{color:#333;}#mermaid-svg-15LHEwEUwVvJS5o7 .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-15LHEwEUwVvJS5o7 .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-15LHEwEUwVvJS5o7 .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-15LHEwEUwVvJS5o7 .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-15LHEwEUwVvJS5o7 .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-15LHEwEUwVvJS5o7 .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-15LHEwEUwVvJS5o7 .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-15LHEwEUwVvJS5o7 #statediagram-barbEnd{fill:#333333;}#mermaid-svg-15LHEwEUwVvJS5o7 .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-15LHEwEUwVvJS5o7 .cluster-label,#mermaid-svg-15LHEwEUwVvJS5o7 .nodeLabel{color:#131300;}#mermaid-svg-15LHEwEUwVvJS5o7 .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-15LHEwEUwVvJS5o7 .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-15LHEwEUwVvJS5o7 .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-15LHEwEUwVvJS5o7 .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-15LHEwEUwVvJS5o7 .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-15LHEwEUwVvJS5o7 .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-15LHEwEUwVvJS5o7 .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-15LHEwEUwVvJS5o7 .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-15LHEwEUwVvJS5o7 .note-edge{stroke-dasharray:5;}#mermaid-svg-15LHEwEUwVvJS5o7 .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-15LHEwEUwVvJS5o7 .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-15LHEwEUwVvJS5o7 .statediagram-note text{fill:black;}#mermaid-svg-15LHEwEUwVvJS5o7 .statediagram-note .nodeLabel{color:black;}#mermaid-svg-15LHEwEUwVvJS5o7 .statediagram .edgeLabel{color:red;}#mermaid-svg-15LHEwEUwVvJS5o7 #dependencyStart,#mermaid-svg-15LHEwEUwVvJS5o7 #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-15LHEwEUwVvJS5o7 .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-15LHEwEUwVvJS5o7 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 被动打开(服务器 bind+listen)
主动打开(客户端发 SYN)
收到 SYN,回 SYN+ACK
收到 SYN+ACK,回 ACK
收到 ACK
主动关闭,发 FIN
收到 FIN(被动关闭)
收到 ACK
收到 FIN,回 ACK
收到 FIN,回 ACK
发 FIN
收到 ACK
等待 2MSL
CLOSED
LISTEN
SYN_SENT
SYN_RCVD
ESTABLISHED
FIN_WAIT_1
CLOSE_WAIT
FIN_WAIT_2
TIME_WAIT
LAST_ACK
三次握手(建立连接)
服务器 客户端 服务器 客户端 #mermaid-svg-JSFTbZiuoMZbs8pK{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-JSFTbZiuoMZbs8pK .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-JSFTbZiuoMZbs8pK .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-JSFTbZiuoMZbs8pK .error-icon{fill:#552222;}#mermaid-svg-JSFTbZiuoMZbs8pK .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-JSFTbZiuoMZbs8pK .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-JSFTbZiuoMZbs8pK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-JSFTbZiuoMZbs8pK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-JSFTbZiuoMZbs8pK .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-JSFTbZiuoMZbs8pK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-JSFTbZiuoMZbs8pK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-JSFTbZiuoMZbs8pK .marker{fill:#333333;stroke:#333333;}#mermaid-svg-JSFTbZiuoMZbs8pK .marker.cross{stroke:#333333;}#mermaid-svg-JSFTbZiuoMZbs8pK svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-JSFTbZiuoMZbs8pK p{margin:0;}#mermaid-svg-JSFTbZiuoMZbs8pK .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-JSFTbZiuoMZbs8pK text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-JSFTbZiuoMZbs8pK .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-JSFTbZiuoMZbs8pK .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-JSFTbZiuoMZbs8pK .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-JSFTbZiuoMZbs8pK .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-JSFTbZiuoMZbs8pK #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-JSFTbZiuoMZbs8pK .sequenceNumber{fill:white;}#mermaid-svg-JSFTbZiuoMZbs8pK #sequencenumber{fill:#333;}#mermaid-svg-JSFTbZiuoMZbs8pK #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-JSFTbZiuoMZbs8pK .messageText{fill:#333;stroke:none;}#mermaid-svg-JSFTbZiuoMZbs8pK .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-JSFTbZiuoMZbs8pK .labelText,#mermaid-svg-JSFTbZiuoMZbs8pK .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-JSFTbZiuoMZbs8pK .loopText,#mermaid-svg-JSFTbZiuoMZbs8pK .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-JSFTbZiuoMZbs8pK .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-JSFTbZiuoMZbs8pK .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-JSFTbZiuoMZbs8pK .noteText,#mermaid-svg-JSFTbZiuoMZbs8pK .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-JSFTbZiuoMZbs8pK .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-JSFTbZiuoMZbs8pK .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-JSFTbZiuoMZbs8pK .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-JSFTbZiuoMZbs8pK .actorPopupMenu{position:absolute;}#mermaid-svg-JSFTbZiuoMZbs8pK .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-JSFTbZiuoMZbs8pK .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-JSFTbZiuoMZbs8pK .actor-man circle,#mermaid-svg-JSFTbZiuoMZbs8pK line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-JSFTbZiuoMZbs8pK :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} CLOSED → LISTEN SYN_SENT SYN_RCVD ESTABLISHED(连接建立) SYN(seq=x)SYN + ACK(seq=y, ack=x+1)ACK(ack=y+1)
四次挥手(断开连接)
服务器(被动关闭) 客户端(主动关闭) 服务器(被动关闭) 客户端(主动关闭) #mermaid-svg-TRmyxt1hIAuoJYL0{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-TRmyxt1hIAuoJYL0 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-TRmyxt1hIAuoJYL0 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-TRmyxt1hIAuoJYL0 .error-icon{fill:#552222;}#mermaid-svg-TRmyxt1hIAuoJYL0 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-TRmyxt1hIAuoJYL0 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-TRmyxt1hIAuoJYL0 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-TRmyxt1hIAuoJYL0 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-TRmyxt1hIAuoJYL0 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-TRmyxt1hIAuoJYL0 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-TRmyxt1hIAuoJYL0 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-TRmyxt1hIAuoJYL0 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-TRmyxt1hIAuoJYL0 .marker.cross{stroke:#333333;}#mermaid-svg-TRmyxt1hIAuoJYL0 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-TRmyxt1hIAuoJYL0 p{margin:0;}#mermaid-svg-TRmyxt1hIAuoJYL0 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-TRmyxt1hIAuoJYL0 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-TRmyxt1hIAuoJYL0 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-TRmyxt1hIAuoJYL0 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-TRmyxt1hIAuoJYL0 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-TRmyxt1hIAuoJYL0 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-TRmyxt1hIAuoJYL0 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-TRmyxt1hIAuoJYL0 .sequenceNumber{fill:white;}#mermaid-svg-TRmyxt1hIAuoJYL0 #sequencenumber{fill:#333;}#mermaid-svg-TRmyxt1hIAuoJYL0 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-TRmyxt1hIAuoJYL0 .messageText{fill:#333;stroke:none;}#mermaid-svg-TRmyxt1hIAuoJYL0 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-TRmyxt1hIAuoJYL0 .labelText,#mermaid-svg-TRmyxt1hIAuoJYL0 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-TRmyxt1hIAuoJYL0 .loopText,#mermaid-svg-TRmyxt1hIAuoJYL0 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-TRmyxt1hIAuoJYL0 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-TRmyxt1hIAuoJYL0 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-TRmyxt1hIAuoJYL0 .noteText,#mermaid-svg-TRmyxt1hIAuoJYL0 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-TRmyxt1hIAuoJYL0 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-TRmyxt1hIAuoJYL0 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-TRmyxt1hIAuoJYL0 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-TRmyxt1hIAuoJYL0 .actorPopupMenu{position:absolute;}#mermaid-svg-TRmyxt1hIAuoJYL0 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-TRmyxt1hIAuoJYL0 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-TRmyxt1hIAuoJYL0 .actor-man circle,#mermaid-svg-TRmyxt1hIAuoJYL0 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-TRmyxt1hIAuoJYL0 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} FIN_WAIT_1 FIN_WAIT_2 CLOSE_WAIT LAST_ACK TIME_WAIT(等 2MSL) → CLOSED → CLOSED FIN(seq=u)ACK(ack=u+1)FIN(seq=v)ACK(ack=v+1)
为什么 TIME_WAIT 要等 2MSL:确保最后一个 ACK 能到达对方(丢了对方会重发 FIN),同时让本次连接残留的旧报文在网络中消散,避免影响新连接。
为什么握手 3 次、挥手 4 次:握手时服务器的 SYN+ACK 可以合并成一个包;挥手时被动方收到 FIN 后,可能还有数据要发,所以 ACK 和 FIN 要分两次发(中间夹着 CLOSE_WAIT 阶段)。
UDP
一般情况下都使用 TCP;选择 UDP 主要是为了处理那些丢包概率不高、但对性能要求很高的场景。
网络层
IP 协议

四位版本号
只有两个取值:4 和 6。
八位服务类型
其中只有 4 位有用,且相互互斥。

16 位总长度
依据该字段,可以进行 IP 分片与重组。
16 位标识
用于标识哪些分片可以组合在一起。
3 位标志
用于控制分片行为。
八位生存时间(TTL)
表示该 IP 数据包还能在网络上传输多久。例如,如果你写错了目标地址,数据包就应当被丢弃。
每经过一个路由器转发一次,该值减 1;减到 0 时被丢弃。
IP 地址短缺与 NAT
核心问题在于 IP 地址数量太多,IPv4 设计时只有约 42 亿个,但使用者众,因此需要解决地址不足的问题。
- 动态分配:需要上网时才分配地址。这只能缓解问题,无法从根本上解决。
- 内网 IP / 私网 IP(NAT,网络地址转换):

在不同的局域网中,IP 地址可以相同。
- 同一局域网内的两个设备互访:直接根据 IP 区分。
- 两个带有外网 IP 的设备互访:外网 IP 全局唯一,与 NAT 无关。
- 两个不同局域网中的设备,以及外网 IP 访问内网 IP:不允许直接访问。
- 内网访问外网:可以访问,但需先执行地址转换。
例子:内网源 IP 为 192.168.xx.xx,路由器公网 IP 为 1.1.1.1。
数据包发出去后,源 IP 被替换为路由器的公网 IP 1.1.1.1(并在 NAT 表中记录映射关系)。
(可以类比学号:只有学号只能在学校内部标识身份;出了学校,你就得用"学号 + 学校"来唯一标识。)
这里被替换的,正是内网源 IP。
在情形 3 和 4 中,虽然网络层不允许直接互访,但我们可以通过应用层来解决。
在情形 3 中:我们架设一个公网 IP,让 A、B 同时连接到该公网 IP,借助它来互相通信。
IPv4 占 4 个字节(2^32)。
IPv6 占 16 个字节(128 位),地址空间为 2^128。
虽然 IPv6 的提出早于 NAT,但它至今仍不主流,原因是它不支持与 IPv4 直接兼容互通。
IP 地址
IP 地址由两部分组成:主机号和网络号。
在同一局域网内,网络号必须相同,主机号必须不同。
在不同局域网内,网络号必须不同。
- 主机号:局域网内主机的标识。
- 网络号:将 IP 地址中的主机位全部置 0,即得到网络号,该地址不能被具体设备使用。
将 IP 地址的主机位全部置 1(二进制全 1),就构成了广播地址。
网络层的广播主要应用于手机投屏等场景。
127.* 常用于本机环回测试,通常为 127.0.0.1。
路由选择
路由器只能选择较优解,而不一定是全局最优解。
如果路由器知道目标在哪,就给出具体路线;否则只给出一个方向。
之所以能这样转发,是因为每个路由器都掌握着一些"线索",通过维护一张路由表来实现。
- 目的 IP(网络号)
- 网络接口(数据从 LAN 口还是 WAN 口出去)
如果没有任何精确路径可走,就走默认路径(即只指明方向,通常是指向上一级路由器)。
例如:我家 → 市 → 省 → 国家 → 世界。
实际场景如查询郑州市:我家 → 洛阳市 → 河南省 → 郑州市。
以太网封装如下:

源地址和目的地址在整个过程中都不改变。
在任意转发阶段,IP 包头里的目的地址始终是郑州市,源 IP 始终是我家。
而以太网报头则是逐段变化的:
- 我家 → 洛阳市
- 洛阳市 → 河南省
- 河南省 → 郑州市
CRC 校验和(差错检测)
用于对数据起到校验作用,检测传输过程中是否发生差错。
DNS:应用层的重要协议
最早期使用的是一个文本文件 hosts。
这种方式维护不便:一旦发生改变,你还得分手动去修改吗?
因此现在有了 DNS 服务器,我们每次访问域名时都先去解析一下。
那么 DNS 服务器的并发量就特别高。
如何防止它宕机?
- 本机会做缓存,短期内再次访问同一域名无需再请求 DNS。
- DNS 本质上是分布式系统,由大量 DNS 服务器组成,一台挂了可以切换到另一台。
小结
本文从下到上梳理了计算机网络的核心原理:
- 应用层:以 XML、JSON、Protobuf 三种数据格式完成请求/响应交换;通过端口号区分进程,一个进程可绑定多端口,一个端口通常只属于一个 socket;DNS 借助本地缓存与分布式架构解决高并发解析。
- 传输层:UDP 简单高效但有 64KB 上限且不保证可靠;TCP 通过确认应答、超时重传、连接管理(三次握手/四次挥手)、滑动窗口、流量控制、拥塞控制、延时应答、捎带应答等十大机制实现可靠传输,并定义了 LISTEN、ESTABLISHED、CLOSE_WAIT、TIME_WAIT 等状态。
- 网络层:IP 协议通过版本号、TTL、分片字段等描述数据包,借助 NAT 缓解地址短缺;IP 地址由网络号与主机号构成;路由选择基于路由表给出较优路径;CRC 校验负责差错检测。
掌握这些基础,能为后续 JavaEE 网络编程与故障排查打下坚实根基。