TCP/IP协议栈深度解析
网络编程是每个后端工程师的基础能力。很多人用HTTP/TCP多年,却从没真正理解过数据包在网络里是怎么走的。本文从原理到实战,帮你彻底搞懂TCP/IP。
一、为什么要分层?分层架构的设计哲学
TCP/IP的设计思想是关注点分离——每一层只做一件事,层与层之间通过标准接口通信。这样任何一层的实现可以独立替换,比如你换了WiFi网卡,上层HTTP代码完全不需要改动。
| 层次 | 协议 | 职责 | 类比 |
|---|---|---|---|
| 应用层 | HTTP/FTP/DNS | 业务数据 | 快递单内容 |
| 传输层 | TCP/UDP | 端到端可靠传输 | 快递员保障送达 |
| 网络层 | IP/ICMP | 路由寻址 | 物流路线规划 |
| 数据链路层 | 以太网/WiFi | 相邻节点传输 | 货车运输 |
| 物理层 | 光纤/电缆 | 比特流传输 | 公路基础设施 |
二、三次握手:为什么不能两次或四次?
三次握手的本质是双方互相确认对方的发送和接收能力都正常,同时同步初始序列号(ISN)。
# 用tcpdump实际抓包观察三次握手
sudo tcpdump -i eth0 'tcp[tcpflags] & (tcp-syn|tcp-ack) != 0' -nn
# 典型输出:
# 10:00:01.001 Client->Server Flags [S] seq=1234567 # SYN
# 10:00:01.002 Server->Client Flags [S.] seq=7654321 ack=1234568 # SYN-ACK
# 10:00:01.003 Client->Server Flags [.] ack=7654322 # ACK
# 为什么不能两次? Server发了SYN-ACK,如果没收到Client的ACK确认
# Server无法知道Client是否收到了自己的SYN-ACK
# 两次握手会让Server维护大量半连接,SYN Flood攻击就利用了这一点
四次挥手断开连接时,Server收到FIN后可能还有数据要发(半关闭状态),所以ACK和FIN分开发送,共需四次。
三、滑动窗口:TCP如何实现高效传输?
如果每发一个包都要等ACK,网络利用率极低。滑动窗口允许发送方在未收到确认的情况下连续发出多个数据包,大幅提升吞吐量。
# 滑动窗口示意图
# 窗口大小=4,已发送=seq 1-4,等待ACK
#
# |已确认|---发送中---|--待发送--|
# | 0 | 1 2 3 4 | 5 6 7 8 |
# 窗口(4)
#
# 收到ACK(1)后,窗口右移
# |已确认|---发送中---|--待发送--|
# | 0-1 | 2 3 4 5 | 6 7 8 9 |
# 查看当前TCP窗口大小
ss -i | grep -A1 'ESTAB' | grep rcv_space
四、拥塞控制:TCP如何与网络和谐共处?
TCP的拥塞控制算法防止发送方把网络打爆,核心有四个阶段:
- 慢开始: 刚连接时cwnd=1,每收到一个ACK就翻倍增长
- 拥塞避免: cwnd超过阈值后线性增长(+1/RTT)
- 快重传: 连续收到3个重复ACK,立刻重传丢失包
- 快恢复: 快重传后cwnd减半,不回到慢开始
五、进阶实操:用Python分析网络延迟
import socket, time, statistics
def tcp_rtt(host, port=80, samples=10):
"""测量TCP连接RTT"""
rtts = []
for _ in range(samples):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(5)
start = time.time()
try:
s.connect((host, port))
rtts.append((time.time() - start) * 1000) # 转ms
finally:
s.close()
time.sleep(0.1)
print(f'平均RTT: {statistics.mean(rtts):.2f}ms')
print(f'最大RTT: {max(rtts):.2f}ms')
print(f'抖动: {statistics.stdev(rtts):.2f}ms')
tcp_rtt('yunduancloud.icu', 443)
六、常见网络问题排查命令
# 查看TCP连接状态统计
ss -s
# 查看TIME_WAIT连接数(过多会耗尽端口)
ss -ant | grep TIME-WAIT | wc -l
# 调整TIME_WAIT超时时间(默认240秒太长)
echo 30 > /proc/sys/net/ipv4/tcp_fin_timeout
# 开启TCP快速回收(高并发服务器必备)
sysctl -w net.ipv4.tcp_tw_reuse=1
# 查看网络丢包情况
netstat -s | grep -i 'retransmit\|fail\|drop'
总结:TCP/IP的精华在于可靠性与性能的平衡设计。三次握手保证双向通信建立,滑动窗口提升吞吐,拥塞控制保护网络。理解这些原理,你处理网络问题会更有方向感。
