【Java SE】TCP/IP协议栈:从分层架构到核心机制

文章目录

一、TCP/IP协议栈整体架构

TCP/IP协议栈采用分层模型,从上到下依次为应用层、传输层、网络层、数据链路层层和物理层。每一层都有明确的职责,通过层间接口协作完成数据传输,上层依赖下层提供的服务,下层为上层屏蔽实现细节。

  • 应用层:面向具体业务,定义数据交互规则
  • 传输层:端到端数据传输,负责可靠性、流量控制(核心协议为TCP、UDP)。
  • 网络层:跨网段路由选择,定义IP地址及数据包转发规则。
  • 数据链路层:物理链路数据传输,处理MAC地址、帧封装及ARP寻址。

这种分层设计的优势在于模块化清晰,某一层的技术升级不会影响其他层的正常工作,极大提升了协议的扩展性和维护性。

二、应用层:业务逻辑的载体

应用层是TCP/IP协议栈的最上层,直接面向用户需求,所有我们熟悉的网络应用都运行在这一层。

核心特点与作用

应用层的核心作用是定义特定业务的数据格式和交互流程,它不关心底层数据如何传输,只专注于满足业务需求。例如:

  • 网页浏览依赖HTTP/HTTPS协议,定义了请求头、响应体的格式及状态码规则。
  • 域名解析依赖DNS协议,实现域名到IP地址的映射,解决IP地址难记忆的问题。
  • 文件传输依赖FTP、TFTP协议,规定了文件上传下载的步骤和数据编码方式。

我们之前编写的Java Socket程序也属于应用层,本质是通过自定义协议完成特定业务。

关键协议

  • DNS:域名系统,底层使用UDP协议实现高效解析,浏览器会缓存DNS结果以提升访问速度。当输入URL后,浏览器首先通过DNS查询目标服务器IP,再发起后续连接。
  • HTTP/HTTPS:超文本传输协议,HTTP基于TCP明文传输,HTTPS通过SSL/TLS加密,常用于网页、接口通信。
  • FTP/SSH:FTP(21端口)用于文件传输,SSH(22端口)用于远程登录,均基于TCP实现可靠传输。

三、传输层:端到端的可靠保障

传输层位于应用层和网络层之间,负责将应用层数据可靠地从发送端传输到接收端,核心是端口号、TCP协议和UDP协议。

端口号:进程的唯一标识

端口号是传输层的核心概念,用于区分同一主机上的不同应用程序,与IP地址配合实现"端到端"通信。

核心特性

  • 端口号范围:0-1023为知名端口号(如HTTP的80、HTTPS的443),由IANA分配;1024-65535为动态端口号,供客户端程序临时使用。
  • 通信标识:通过"源IP+源端口+目的IP+目的端口+协议号"五元组唯一标识一个网络通信,可通过netstat -n命令查看。

注意:

  • 一个进程可以绑定多个端口号:例如服务器可同时监听80(HTTP)和443(HTTPS)端口。
  • 一个端口号不能被多个进程绑定:端口号是进程的唯一标识,同一时间只能被一个进程占用。

UDP协议:轻量无连接传输

UDP(用户数据报协议)是一种简单的传输层协议,传输过程类似寄信,无需提前建立连接。

协议格式

UDP首部仅8字节,分成四个字段:源端口、目的端口、长度(整个数据报最大64K)和校验和(校验出错直接丢弃),每个字段各两字节,16位。

核心特点

  • 无连接:知道对端IP和端口即可直接发送,无需三次握手。
  • 不可靠:无确认应答和重传机制,数据丢失不会通知应用层。
  • 面向数据报:应用层交付的报文原样发送,不拆分、不合并。

适用场景与注意事项

  • 适用场景:实时性要求高、允许少量丢包的场景,如视频通话、语音聊天、DNS解析。
  • 注意事项:若传输数据超过64K,需在应用层手动分包、拼装;基于UDP的应用层协议包括NFS、DHCP、DNS等。

TCP协议:可靠的面向连接传输

TCP(传输控制协议)是传输层的核心协议,专为可靠传输设计,通过一系列机制解决丢包、乱序、重传等问题,是大多数核心业务的首选。

协议格式

TCP首部最小20字节(4*5),最大60字节

  • 16位源端口号与16位目的端口号:传输的核心内容
  • 4位首部长度:4bit:0-15,由于选项存在,导致TCP报头长度是可变的。这里以4字节为单位。15对应的长度就是60字节
  • 选项:补充信息,可有可无
  • 32位序号/确认序号:用于按序传输和确认接收。
  • 保留位:为未来扩展信息留出操作空间
  • 6位标志位:SYN(建立连接)、ACK(确认应答)、FIN(关闭连接)、RST(重置连接)、PSH(立即推送)、URG(紧急数据)。
  • 16位窗口大小:用于流量控制,告知发送端当前可接收的最大数据量。

核心机制

1. 确认应答

TCP为每个字节编号,编号是连续递增的。

在序号部分填写载荷部分第一个字节的序号;接收端收到数据后返回确认序号,填写收到的数据载荷最后一个字节序号+1,也就是表示<1001的数据都收到了,下一次从1001开始发送,确保数据不丢失。

TCP报头不参与编号,序号和确认序号都是针对载荷的

数据发送存在后发先至的情况,序号就可以为数据排序,保证应用程序通过socket api读到的数据(InputStream)顺序和对方写入的数据顺序(OutputStream)正确的。

TCP 会在接收方安排的接收缓冲区(内存中,操作系统内核里)通过网卡读到的数据,先放到缓冲区里面,后续代码调用read。再从缓冲区中读取。

缓冲区中根据序号排队,确保前面的数据收到,read才会解除阻塞;如果后面数据先到,read则会继续阻塞,不会读取数据。

基于TCP写代码不需要担心顺序问题,而基于UDP,实现拆包组包,需要考虑顺序,就会麻烦很多。

2. 超时重传

当A给B发送数据,在一定时间内A没有收到ACK,A就认为发生丢包了。

通过引入超时时间来判断是否丢包。发送端未在规定时间内收到确认,会重传数据。超时时间动态调整,初始为500ms,重传后按2倍、4倍递增,累计多次失败则关闭连接。

当超时次数或者等待时间达到一定限度,就会认为是网络出现故障,放弃这次传输。

当A没有收到ACK,可能是 A->B 发送数据过程中丢包,也可能是 B->A 返回ACK过程中丢包。但是A无法判断是哪种情况,都会进行重传。

  • 如果是 A->B 数据丢失,重传可以解决;
  • 如果 B->A 过程中ACK丢失,A再重传,就会导致B收到两份一样的数据。在接收缓冲区会根据序号进行去重操作(排序操作),如果存在则丢弃;不存在则放入。保证应用程序只收到一份数据。

确认应答超时重传是TCP最核心的两个机制,保证了TCP进行可靠传输。

3. 连接管理

通过三次握手建立连接,四次挥手关闭连接。握手或挥手操作发送不携带业务的数据,通过这个数据"跟对方打个招呼"。

(1) 建立连接

SYN是指synchronized,同步。与多线程的概念不同,这里的同步指"数据上的同步",A告诉B,接下来我要和你建立连接,需要你把我的关键信息保存下来,同时你也要把你的信息同步给我。把TCP报头的SYN部位填1,表示同步报文。

B确认应答ack和发送syn可以合并,这样就是"三次握手"。

注意:

  1. 关键信息包括IP端口号。IP保存在携带着TCP的IP报头中;端口号保存在TCP报头中。而sync和ack都不携带载荷。
  2. 客户端发起syn。客户端和服务器只是角色,同一程序在不同场景可以扮演不同角色,主动的一方是客户端。
  3. syn和ack都是内核负责的,与用户代码无关。可以保证是同一时机发送,这样就可以合并。

思考: 三次握手有什么意义?解决了哪些问题?

  1. 三次握手相当于"投石问路",先初步探查网络的通信链路是否通畅。
  2. 验证通信双方发送能力和接收能力是否正常。
    如果只握手两次,无法让双方都确认收发能力正常,因此三次握手是必不可少的。而四次握手又没必要。
  3. 协商一些关键信息。例如序号从几开始。
    初始序号一般不从0开始,因为传输过程中存在丢包现象。
    举个例子:第一次传输由1000开始,这过程中可能有数据迷路;第二次传输由8000开始,如果此时第一次传输中迷路的数据才到达,就可以很好的判断出这不是有用的数据,可以丢弃。

(2)断开连接
四次挥手不可以合并,因为ACK和FIN两次交互的时机不一定相同。内核收到FIN会第一时间返回ACK,与应用程序的代码无关;第二个FIN则是代码调用socket.close或者进程结束才会触发。第二个FIN与ACK很可能不处于同一时机。

三次握手中,一定是客户端主动发起SYN(第一次握手一定是客户端开头);四次挥手中,客户端与服务端都可以主动发起FIN,取决于谁先调用close,实际开发中,客户端主动断开连接的可能性比较大。

借助TCP服务器部分的代码理解四次回挥手:

异常情况:服务器始终不调用close,站在A的视角上,A已经给B把FIN发了很久,B没有后续的挥手操作,A就会主动释放连接(也就是把B的核心信息删掉);站在B的视角上,由于代码有bug,连接还存在,虽然还保存对方信息,但是无法进行正常的数据通信了

4. 滑动窗口

无需等待每段数据的ACK,可连续发送多个数据段,提升传输效率。窗口大小越大,吞吐量越高,由操作系统通过发送缓冲区维护。

一直持续发送,不等待,显然是不科学的,因为这样就没有可靠性了

如果2001ack比1001先到,那么就不需要等待1001ack,直接往后走两个格子就行。因为确认序号本身的含义就是当前序号之前的数据全部收到,可以从当前序号开始发送。2001ack本身就包含1001ack。

注意:

  1. 窗口越大,批发量数据就越多,效率就越高。但是窗口不能无限大,会影响可靠性。
  2. 滑动窗口只是在可靠传输的基础上提高效率。引入可靠性肯定会使效率折损,不可能会比UDP还高。

丢包问题:

  1. 丢ack

    后一个ack可以涵盖前一个ack,因此不需要做任何处理

  2. 丢数据

快速重传: 只是谁丢了,就重传谁,其他已收到的数据无需再重传,整个重传过程是很快的

注意: 超时重传和快速重传是针对不同情况的重传机制,并不矛盾。

  • 超时重传:传输的数据量小,没有构成滑动窗口的批量传输机制
  • 快速重传:传输的数据量大,可以形成滑动窗口
5. 流量控制

滑动窗口,窗口越大,效率就越高。但窗口不能无限大,接收方的处理能力是有上限的,这里的上限与代码逻辑有关。

把接收缓冲区理解为蓄水池,发送的速度就相当于蓄水的速度;应用程序从缓冲区汇总读取数据就相当于放水(每读一个字节,就可以把这个字节从缓冲区中删除了)。如果"水溢出"就会丢包。

补充:

  1. 每个Socket对象都对应一组接收缓冲区和发送缓冲区。也就是说一个程序创建了N个Socket对象就会有N个发送缓冲区和接收缓冲区。
  2. 在Java中创建Socket对象(Socket clientSocket = new Socket())内核中的文件描述符表就会多一项文件对象,这个文件对象包括发送缓冲区和接收缓冲区(都是字节数组)

流量控制就是让发送方"踩刹车",

接收端通过窗口大小字段告知发送端自身缓冲区状态,避免发送过快导致缓冲区溢出。缓冲区满时窗口置为0,发送端停止发送并定期探测。

6. 拥塞控制

通过慢启动、拥塞避免、快重传、快恢复机制,避免网络拥堵。慢启动阶段拥塞窗口指数增长,超过阈值后线性增长,丢包时调整阈值并重置窗口。

7. 延迟应答与捎带应答

延迟应答(200ms内或每接收2个包应答)可增大窗口大小;捎带应答将ACK与应用层数据一起发送,减少网络开销。

面向字节流与粘包问题

  • 面向字节流:TCP将应用层数据视为连续字节流,通过发送缓冲区和接收缓冲区实现读写解耦。例如发送端分10次写1字节,接收端可一次读10字节。
  • 粘包问题:TCP无数据边界,应用层需自行定义边界,解决方案包括:定长包、包头加长度字段、使用分隔符。

TCP与UDP对比

特性 TCP UDP
连接方式 面向连接(三次握手) 无连接
可靠性 可靠(确认、重传、排序) 不可靠(无确认重传)
传输效率 较低(机制复杂、开销大) 较高(首部简单、无开销)
适用场景 文件传输、接口通信、登录 视频通话、语音、DNS解析

四、网络层:跨网段的路由导航

网络层的核心作用是在复杂网络中找到合适的传输路径,实现跨网段数据转发,核心是IP协议、地址管理和路由选择。

IP协议:网络层的核心

IP协议定义了IP地址格式和数据包转发规则,是跨网段通信的基础。

协议格式

IP首部最小20字节,关键字段包括:

  • 版本号:IPv4(32位地址)和IPv6(128位地址),目前IPv6正在逐步普及。
  • 总长度:IP数据包总字节数,最大65535字节。
  • TTL(生存时间):默认64,每经过一个路由器减1,避免路由循环导致数据包无限转发。
  • 源IP/目的IP:标识发送端和接收端的网络地址。

核心功能

  • 地址标识:通过IP地址唯一标识网络中的主机或路由器。
  • 路由转发:路由器收到IP数据包后,根据目的IP查询路由表,转发到下一跳。

地址管理:IP地址的分配与划分

IP地址是网络层的核心标识,分为网络号和主机号两部分,用于区分不同网段和同一网段内的主机。

分类与CIDR

  • 传统分类:将IP分为A、B、C、D、E类,A类(0.0.0.0-127.255.255.255)适用于大型网络,B类(128.0.0.0-191.255.255.255)适用于中型网络,但存在地址浪费问题。
  • CIDR(无类域间路由):通过子网掩码区分网络号和主机号,例如192.168.1.1/24表示子网掩码前24位为1(255.255.255.0),网络号为192.168.1.0,主机号范围0-255。

私有IP与公网IP

  • 私有IP:用于局域网内部通信,无需注册,包括10.、172.16.-31.、192.168.*,不同局域网可重复使用。
  • 公网IP:用于互联网通信,全球唯一,需向运营商申请。

IP地址不足的解决方案

  • DHCP:动态分配IP地址,仅给接入设备分配地址,提高利用率。
  • NAT:网络地址转换,路由器将私有IP转为公网IP,实现多设备共享一个公网IP。
  • IPv6:128位地址空间,彻底解决IP不足问题,我国IPv6活跃用户数已达7.67亿。

路由选择:跨网段的路径规划

路由选择是网络层的核心功能,指路由器根据路由表确定IP数据包的转发路径,过程类似"一跳一跳问路"。

路由表

路由器维护一张路由表,包含目的网络地址、子网掩码、下一跳地址、发送接口等信息,可通过route命令查看。

  • 直连路由:目的网络与路由器直接相连,无需转发。
  • 静态路由:由管理员手动配置。
  • 动态路由:通过路由协议(如OSPF、RIP)自动生成。

转发过程

以目的IP为202.10.1.2为例:

  1. 主机查询路由表,发现无匹配条目。
  2. 按默认路由将数据包发送到网关路由器(如192.168.10.1)。
  3. 网关路由器根据自身路由表转发数据包,依次经过多个路由器,最终到达目标主机。

五、数据链路层:物理链路的传输基础

数据链路层位于网络层之下,负责处理物理链路的帧封装、MAC地址寻址、MTU限制等问题,确保数据在相邻设备间可靠传输。

以太网:主流的局域网技术

以太网是数据链路层的主流技术标准,规定了网线类型(双绞线)、传输速率(10M/100M/1000M)、帧格式等。

以太网帧格式

以太网帧长度为46-1500字节,核心字段包括:

  • 目的MAC/源MAC:6字节,网卡出厂固化的硬件地址,用于相邻设备寻址。
  • 类型字段:标识上层协议(如0800对应IP协议)。
  • CRC校验码:验证帧数据的完整性,校验出错则丢弃。

MAC地址与IP地址的区别

  • IP地址:描述"终点地址",类似快递的收件人地址,跨网段有效。
  • MAC地址:描述"区间起点/终点",类似快递的每一段运输节点地址,仅在相邻设备间有效。

例如:从主机A发送数据到外网主机B,IP地址始终是A和B的地址,而MAC地址在每一跳都会变为当前路由器和下一跳路由器的地址。

MTU:最大传输单元

MTU是数据链路层对帧数据的最大限制,以太网MTU为1500字节,超过则需分片。

对上层协议的影响

  • IP协议:超过MTU的IP数据包会被分片,每个分片有相同的标识号,接收端重组后交给上层。任意分片丢失则重组失败,IP层不负责重传。
  • UDP协议:UDP数据报最大长度为64K,若数据超过1472字节(1500-20IP首部-8UDP首部),会被IP分片,丢失概率增加,因此UDP适合传输小包。
  • TCP协议:通过MSS(最大分段大小)协商避免分片,MSS=MTU-IP首部-TCP首部,建立连接时双方通过SYN报文告知自身MSS,选择较小值作为最终标准。

ARP协议:IP与MAC的映射桥梁

ARP(地址解析协议)介于数据链路层和网络层之间,负责将IP地址转换为MAC地址,解决"知道IP但不知道MAC"的寻址问题。

工作流程

  1. 主机A想与主机B(IP:172.20.1.2)通信,查询本地ARP缓存表,若无B的MAC地址,则发送ARP广播(目的MAC:FF:FF:FF:FF:FF:FF)。
  2. 同一网段内所有主机接收广播,仅主机B发现IP匹配,返回ARP应答,包含自身MAC地址。
  3. 主机A将B的IP-MAC映射存入ARP缓存表(过期时间20分钟),后续通信直接使用该映射。

六、TCP/IP协议的实际应用与面试重点

经典应用场景

  • 服务器开发:需深入理解TCP的连接管理、滑动窗口、拥塞控制,避免CLOSE_WAIT状态堆积(需正确调用close关闭socket)。
  • 网络编程:UDP适合实时通信,需手动处理分包、重传;TCP适合可靠传输,需解决粘包问题(定长包、长度字段、分隔符)。
  • 网络故障排查:通过netstat查看连接状态,arp -a查看ARP缓存,route查看路由表,定位丢包、连接失败等问题。

高频面试题解析

  1. TCP三次握手和四次挥手的原因:三次握手确保双方收发能力正常,四次挥手因TCP全双工,需分别关闭发送和接收通道。
  2. TIME_WAIT状态的作用:持续2MSL(报文最大生存时间),确保迟到的报文消失,避免端口复用导致的数据错误。
  3. 用UDP实现可靠传输:参考TCP机制,在应用层实现序列号、确认应答、超时重传、滑动窗口等功能。
  4. NAT的优缺点:优点是解决IP不足,无需更新硬件;缺点是无法从外部访问内部服务器,转换表维护有开销。

七、总结

TCP/IP协议栈是一个层层递进、相互协作的复杂系统,每一层都有明确的职责和核心技术:

  • 应用层定义业务规则,是协议栈的"上层建筑"。
  • 传输层通过TCP/UDP和端口号,实现端到端的可靠或高效传输。
  • 网络层通过IP地址和路由选择,实现跨网段的路径规划。
  • 数据链路层通过MAC地址和帧封装,实现物理链路的可靠传输。
相关推荐
七宝大爷1 小时前
Transformer架构变体全景图:从BERT到GPT的演化路径
架构·bert·transformer
CoderYanger1 小时前
递归、搜索与回溯-综合练习:22.优美的排列
java·算法·leetcode·深度优先·1024程序员节
想做后端的前端1 小时前
Lua基本数据类型
java·junit·lua
张人大 Renda Zhang1 小时前
Maven = Java 构建世界的“事实标准”:从 pom.xml 到云原生 CI/CD
xml·java·spring boot·后端·ci/cd·云原生·maven
shayudiandian1 小时前
【Java】内部类
java
老鼠只爱大米1 小时前
Java设计模式之装饰器模式详解
java·设计模式·装饰器模式·decorator·java设计模式
0***v7771 小时前
springboot 异步操作
java·spring boot·mybatis
小毅&Nora1 小时前
【云计算】【Kubernetes】 ② K8S的架构、应用及源码解析 - Pod 生命周期管理与 CRI 集成详解
架构·kubernetes·云计算
LSL666_1 小时前
7 SpringBoot pom.xml解释
java·spring boot·spring