深入理解网络分层模型与协议原理
| OSI 七层 | TCP/IP 四层 | 主要协议 | 功能 |
|---|---|---|---|
| 应用层 | 应用层 | HTTP, FTP, SMTP, DNS | 为应用程序提供网络服务 |
| 表示层 | - | 数据格式转换、加密 | |
| 会话层 | - | 建立、管理、终止会话 | |
| 传输层 | 传输层 | TCP, UDP | 端到端通信、可靠传输 |
| 网络层 | 网络层 | IP, ICMP, ARP | 路由选择、逻辑寻址 |
| 数据链路层 | 网络接口层 | Ethernet, PPP | 帧封装、MAC 寻址 |
| 物理层 | 物理介质 | 比特流传输 |
核心区别:
| 特性 | TCP | UDP |
|---|---|---|
| 连接 | 面向连接(三次握手) | 无连接 |
| 可靠性 | 可靠传输(确认、重传) | 不可靠(尽最大努力交付) |
| 顺序 | 保证顺序 | 不保证顺序 |
| 速度 | 较慢(开销大) | 快速(开销小) |
| 头部大小 | 20 字节 | 8 字节 |
| 流量控制 | 有(滑动窗口) | 无 |
| 拥塞控制 | 有 | 无 |
TCP 适用场景:
UDP 适用场景:
IP 地址是互联网协议地址,用于在网络中唯一标识一台设备。
| 特性 | IPv4 | IPv6 |
|---|---|---|
| 地址长度 | 32 位(4 字节) | 128 位(16 字节) |
| 地址数量 | 约 43 亿(2^32) | 约 3.4×10^38 |
| 表示方式 | 点分十进制 192.168.1.1 | 冒号十六进制 2001:0db8::1 |
| 地址分配 | 手动/DHCP | 自动配置(SLAAC) |
| 安全性 | 可选(IPSec) | 内置(IPSec) |
| 头部大小 | 20-60 字节 | 固定 40 字节 |
子网掩码用于区分 IP 地址中的网络部分和主机部分,通过与 IP 地址进行按位与运算得到网络地址。
| CIDR 表示 | 子网掩码 | 可用主机数 |
|---|---|---|
| /24 | 255.255.255.0 | 254 |
| /25 | 255.255.255.128 | 126 |
| /26 | 255.255.255.192 | 62 |
| /27 | 255.255.255.224 | 30 |
| /28 | 255.255.255.240 | 14 |
| /30 | 255.255.255.252 | 2(点对点链路) |
将 192.168.1.0/24 划分为 4 个子网:
原网络:192.168.1.0/24(256 个地址)
划分为 4 个子网,需要借 2 位(2^2 = 4)
新子网掩码:/26(255.255.255.192)
子网 1:192.168.1.0/26 (192.168.1.0 ~ 192.168.1.63)
子网 2:192.168.1.64/26 (192.168.1.64 ~ 192.168.1.127)
子网 3:192.168.1.128/26 (192.168.1.128 ~ 192.168.1.191)
子网 4:192.168.1.192/26 (192.168.1.192 ~ 192.168.1.255)
每个子网:64 个地址,62 个可用主机(去掉网络地址和广播地址)ARP 用于将 IP 地址解析为 MAC 地址,工作在网络层和数据链路层之间。
硬件类型(2 字节):1 表示以太网
协议类型(2 字节):0x0800 表示 IPv4
硬件地址长度(1 字节):6(MAC 地址长度)
协议地址长度(1 字节):4(IPv4 地址长度)
操作码(2 字节):1=请求,2=响应
发送方 MAC 地址(6 字节)
发送方 IP 地址(4 字节)
目标 MAC 地址(6 字节):请求时为全 0
目标 IP 地址(4 字节)arp -a(Windows/Linux)ICMP 是网络层协议,用于在 IP 主机、路由器之间传递控制消息,报告错误和测试连通性。
| 类型 | 代码 | 描述 | 用途 |
|---|---|---|---|
| 0 | 0 | Echo Reply | ping 响应 |
| 3 | 0-15 | Destination Unreachable | 目标不可达 |
| 5 | 0-3 | Redirect | 重定向 |
| 8 | 0 | Echo Request | ping 请求 |
| 11 | 0-1 | Time Exceeded | TTL 超时 |
# ping 示例
$ ping www.baidu.com
PING www.a.shifen.com (14.215.177.38): 56 data bytes
64 bytes from 14.215.177.38: icmp_seq=0 ttl=54 time=8.123 ms
64 bytes from 14.215.177.38: icmp_seq=1 ttl=54 time=7.891 ms
# 参数说明
# ttl: Time To Live,经过的路由器跳数
# time: 往返时间(Round Trip Time)通过逐步增加 TTL 值,探测数据包到达目标的路径。
# traceroute 示例(Linux)
$ traceroute www.baidu.com
traceroute to www.a.shifen.com (14.215.177.38), 30 hops max
1 192.168.1.1 (192.168.1.1) 1.234 ms
2 10.0.0.1 (10.0.0.1) 5.678 ms
3 * * * # 某些路由器不响应
4 14.215.177.38 (14.215.177.38) 8.901 ms
# Windows 使用 tracert 命令超时重传(RTO - Retransmission Timeout):
# RTO 计算(简化版)
SRTT = (1 - α) × SRTT + α × RTT_sample # 平滑 RTT
RTTVAR = (1 - β) × RTTVAR + β × |SRTT - RTT_sample| # RTT 方差
RTO = SRTT + 4 × RTTVAR
# 典型值:α = 1/8, β = 1/4快速重传(Fast Retransmit):
SACK(Selective Acknowledgment):
滑动窗口机制:
# 滑动窗口示例
发送窗口 = min(拥塞窗口, 接收窗口)
接收方缓冲区:[已读取][已接收未读][可接收]
↑
窗口大小(在 TCP 头部通告)
# 零窗口探测
当接收窗口为 0 时,发送方定期发送 1 字节探测包四个核心算法:
① 慢启动(Slow Start):
② 拥塞避免(Congestion Avoidance):
③ 快速重传(Fast Retransmit):
④ 快速恢复(Fast Recovery):
# 拥塞控制状态转换
初始状态:慢启动
↓ cwnd >= ssthresh
拥塞避免
↓ 超时
慢启动(ssthresh = cwnd/2, cwnd = 1)
↓ 3 个重复 ACK
快速恢复(ssthresh = cwnd/2, cwnd = ssthresh + 3)
↓ 新 ACK
拥塞避免(cwnd = ssthresh)TCP 是面向字节流的协议,没有消息边界概念,可能出现:
1. 固定长度:
// 每个消息固定 100 字节
byte[] buffer = new byte[100];
while (true) {
int read = inputStream.read(buffer);
if (read == 100) {
processMessage(buffer);
}
}2. 分隔符:
// 使用 \n 作为消息分隔符
BufferedReader reader = new BufferedReader(
new InputStreamReader(socket.getInputStream())
);
String message;
while ((message = reader.readLine()) != null) {
processMessage(message);
}3. 消息头 + 长度:
// 前 4 字节表示消息长度
DataInputStream dis = new DataInputStream(socket.getInputStream());
while (true) {
int length = dis.readInt(); // 读取长度
byte[] data = new byte[length];
dis.readFully(data); // 读取完整消息
processMessage(data);
}
// 发送端
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
byte[] message = "Hello".getBytes();
dos.writeInt(message.length); // 写入长度
dos.write(message); // 写入数据4. 使用应用层协议:
// Netty 示例
pipeline.addLast(new LengthFieldBasedFrameDecoder(
1024, // 最大帧长度
0, // 长度字段偏移
4, // 长度字段长度
0, // 长度调整
4 // 跳过的字节数
));NAT(Network Address Translation)用于将私有 IP 地址转换为公网 IP 地址,解决 IPv4 地址不足问题。
内网主机无法被外网主动访问,解决方案:
端口号是传输层协议用于标识应用程序的 16 位整数(0-65535)。
| 端口 | 协议 | 服务 |
|---|---|---|
| 20/21 | TCP | FTP(数据/控制) |
| 22 | TCP | SSH |
| 23 | TCP | Telnet |
| 25 | TCP | SMTP(邮件发送) |
| 53 | UDP/TCP | DNS |
| 80 | TCP | HTTP |
| 110 | TCP | POP3(邮件接收) |
| 143 | TCP | IMAP |
| 443 | TCP | HTTPS |
| 3306 | TCP | MySQL |
| 3389 | TCP | RDP(远程桌面) |
| 6379 | TCP | Redis |
| 8080 | TCP | HTTP 备用端口 |
主动关闭方在发送最后一个 ACK 后进入 TIME_WAIT 状态,等待 2MSL(Maximum Segment Lifetime)时间。
net.ipv4.tcp_fin_timeout 调整)# Linux 系统参数调优
# 允许 TIME_WAIT 套接字重用
net.ipv4.tcp_tw_reuse = 1
# 快速回收 TIME_WAIT 套接字(不推荐)
net.ipv4.tcp_tw_recycle = 0 # 新版本已废弃
# 减少 FIN_WAIT_2 超时时间
net.ipv4.tcp_fin_timeout = 30
# 增加本地端口范围
net.ipv4.ip_local_port_range = 10000 65535sendfile():文件到 socket 直接传输mmap():内存映射文件