深入浅出计算机网络:从 TCP 可靠传输到 DNS 解析核心原理

应用层相关协议

本文系统梳理计算机网络的核心原理,从应用层的数据交换格式与端口号,到传输层 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 主要适用于以下场景:

  1. 本身不容易丢包(既然 UDP 不关心是否丢包,那么在该场景下不丢包即可满足需求)。
  2. 对传输效率要求高。

校验和:类似于 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。

这就是滑动窗口,本质上属于"亡羊补牢"------在效率已经存在损失的前提下,尽可能减少损失。

那么窗口内的丢包如何处理?

  1. ACK 丢失:不管它,因为后一个 ACK 能够覆盖前一个。
  2. 数据丢失:

为何要多次确认 1001?是为了防止这部分数据只是"卡住了",而非"丢了"。

如果你发送数据的速度很慢,就不会构成滑动窗口。

5. 流量控制

流量控制用于保证可靠性:如果发送速度过快,接收方可能处理不过来,导致接收方不得不丢弃新到的数据。

接收方维护一个接收缓冲区,当数据积累到一定程度、缓冲区满了,新数据就会被丢弃。

因此,流量控制就是根据接收方的处理能力,反向控制发送方的发送速率。

接收方再通过 ACK 把剩余窗口大小带回去。

如果剩余窗口变为 0,发送方会周期性地发送一个不含数据的探测包,询问对方当前还有多少剩余空间。

注意:以上都属于"可靠性"范畴,而非"安全性"。

6. 拥塞控制

拥塞控制与流量控制类似,都是对滑动窗口作出限制。

流量控制依据的是接收方的处理能力。

拥塞控制依据的是整条通信路径的处理能力。

(也就是说,因为数据传输要依赖多个路由器转发,若中间某个路由器处理速度慢,数据就会堆积在那里。)

基本思路是"试探":丢包了就减速,没丢包就加速。

即"面多加水,水多加面"。

具体做法是维护一个 int 变量来描述窗口大小。

实际发送窗口大小为:min(流量控制窗口, 拥塞窗口)

最开始窗口很小,随后指数级增长。

当增长到超过某个设定阈值后,转为线性增长;一旦中途发生丢包,窗口就缩小。

7. 延时应答

延时应答的目的是在尽可能的情况下扩大窗口。

如果我们立即返回 ACK,应用层只处理了一点点数据,因此窗口较小。

如果我们不立即返回 ACK,应用层可能已处理了一部分数据,从而能通告更大的窗口。

8. 捎带应答

正常模式是一问一答。

我先询问,对方确认收到;对方再应答,我确认收到。

但配合延时应答,对方可以直接把"应答"和"确认收到"合并发送给我。

这也是四次挥手能够变成三次挥手的原因。

9. 面向字节流与粘包问题

这是"粘包问题"的来源之一。

先解释一下粘包:

假设我发了两个包,一个是 a,另一个是 b

我希望对方先接收 a、再接收 b,但两个包都进入了缓冲区。

结果对方一次性全部读取,变成了 a+b

下面是拆包:

也有可能是我发的是 a+b,但接收方读取较快,变成了先 ab

TCP 不关心你应用层的数据包是如何划分的,因为包与包之间没有明确的界限,必须在应用层自行处理。

10. 异常情况处理
1. 进程崩溃

无论以何种方式退出,操作系统都会自动进行清理和资源回收。

2. 主机正常关机

如果关机速度正常,四次挥手能够跑完。

若关机速度太快,四次挥手无法跑完:

  • 服务器最后发出 FIN,你这边没有回应。
  • 服务器开始重传。
  • 最终服务端删除此前保留的你的相关信息。
  • 一切恢复正常。
3. 主机掉电/关机

程序完全无法进行挥手操作。

  1. 接收方关机:

    • 无法给发送方传 ACK。
    • 发送方重传。
    • 发送方一直收不到 ACK。
    • 发送方放弃连接,发送复位报文(RST)。
  2. 发送方关机:

    • 接收方傻眼了:发方是挂了,还是只是休息一会?
    • 接收方会不时发一个空包(心跳包),即询问"你在不在",目的是触发对方的 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 亿个,但使用者众,因此需要解决地址不足的问题。

  1. 动态分配:需要上网时才分配地址。这只能缓解问题,无法从根本上解决。
  2. 内网 IP / 私网 IP(NAT,网络地址转换):

在不同的局域网中,IP 地址可以相同。

  1. 同一局域网内的两个设备互访:直接根据 IP 区分。
  2. 两个带有外网 IP 的设备互访:外网 IP 全局唯一,与 NAT 无关。
  3. 两个不同局域网中的设备,以及外网 IP 访问内网 IP:不允许直接访问。
  4. 内网访问外网:可以访问,但需先执行地址转换。

例子:内网源 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 服务器的并发量就特别高。

如何防止它宕机?

  1. 本机会做缓存,短期内再次访问同一域名无需再请求 DNS。
  2. DNS 本质上是分布式系统,由大量 DNS 服务器组成,一台挂了可以切换到另一台。

小结

本文从下到上梳理了计算机网络的核心原理:

  • 应用层:以 XML、JSON、Protobuf 三种数据格式完成请求/响应交换;通过端口号区分进程,一个进程可绑定多端口,一个端口通常只属于一个 socket;DNS 借助本地缓存与分布式架构解决高并发解析。
  • 传输层:UDP 简单高效但有 64KB 上限且不保证可靠;TCP 通过确认应答、超时重传、连接管理(三次握手/四次挥手)、滑动窗口、流量控制、拥塞控制、延时应答、捎带应答等十大机制实现可靠传输,并定义了 LISTEN、ESTABLISHED、CLOSE_WAIT、TIME_WAIT 等状态。
  • 网络层:IP 协议通过版本号、TTL、分片字段等描述数据包,借助 NAT 缓解地址短缺;IP 地址由网络号与主机号构成;路由选择基于路由表给出较优路径;CRC 校验负责差错检测。

掌握这些基础,能为后续 JavaEE 网络编程与故障排查打下坚实根基。

相关推荐
kels88994 小时前
实战排坑:黄金实时API开发,XAUUSD Tick报文异常处理实践
开发语言·python·websocket·网络协议·信息可视化
Bobolink_4 小时前
IP更换频率:账号运营里多久换一次IP算正常
大数据·网络协议·tcp/ip
treesforest5 小时前
你的IP干净吗?
网络·网络协议·tcp/ip·跨境电商·ip归属地查询·跨境
sbjdhjd5 小时前
大三网安秋招核心学习前言(AI 安全 + Web 漏洞 + 内网渗透全考点)
人工智能·网络协议·学习·安全·网络安全·开源·php
峥无6 小时前
《TCP/IP协议栈详解:协议分层·封装分用·地址管理》
网络·网络协议·tcp/ip
只吃不吃香菜7 小时前
Windows 下基于 YAML 规则的指定域名分流:以哔哩哔哩为例
网络·网络协议·计算机网络·网络安全·代理模式
我爱cope7 小时前
【计算机网络 | 数据链路层2:差错检测与纠正:奇偶校验、校验和、CRC 分别怎么工作?】
网络·学习·计算机网络
雾时之林8 小时前
Linux---计算机网络常见面试题
linux·运维·计算机网络
GDAL17 小时前
Nginx TCP/UDP四层转发(Stream模块)完整深入教程
tcp/ip·nginx·udp