之前我们聊过 Shell、Git、数据结构这些 CS 基础,这次来补一个更底层的知识——TCP/IP 协议栈。不管你是做 Web 开发、写爬虫还是搞分布式系统,网络协议都是绕不开的。今天我们用学习笔记的方式,从上到下把四层模型过一遍,顺便用 Python socket 写个小程序加深理解。
一、TCP/IP 四层模型概览
你可能听过 OSI 七层模型,但在实际工程中我们更常说的是 TCP/IP 四层模型。它把网络通信抽象成四层,每一层各司其职:
- Application Layer(应用层):HTTP、HTTPS、DNS、FTP、SMTP 等,我们写代码直接打交道的一层。
- Transport Layer(传输层):TCP 和 UDP,负责端到端的可靠传输。
- Internet Layer(网络层):IP、ICMP、ARP,负责路由和寻址,把数据包从源主机送到目的主机。
- Network Access Layer(网络接入层):Ethernet、Wi-Fi,处理物理传输。
💡 简单记忆:应用层管「说什么」,传输层管「怎么可靠地送到」,网络层管「送到哪」,接入层管「用什么物理线路送」。
数据从应用层往下走的时候,每一层都会加上自己的 header,这个过程叫 encapsulation(封装)。到了对端再从下往上逐层拆 header,叫 decapsulation(解封装)。就像套娃一样,一层包一层。
二、IP 协议:网络层的核心
IP(Internet Protocol) 是整个互联网的基础。它做的事情很简单:给每个设备分配一个地址(IP address),然后把数据包从源地址路由到目的地址。
IPv4 地址是 32 位的,比如 192.168.1.1。因为地址不够用,后来又搞了 IPv6(128 位)。IP 协议本身是不可靠的——它只管「尽力而为」地把包送出去,不保证一定送到,也不保证顺序。所以才需要上层的 TCP 来保证可靠性。
一个 IP packet 的关键字段:
- Version:IPv4 还是 IPv6
- Source / Destination IP:源地址和目的地址
- TTL(Time to Live):防止数据包在网络中无限循环,每经过一个路由器减 1
- Protocol:上层协议类型,比如 TCP 是 6,UDP 是 17
三、TCP:可靠的传输层协议
TCP(Transmission Control Protocol) 是面向连接的、可靠的、基于字节流的传输层协议。它在 IP 的基础上加了一堆机制来保证数据不丢、不乱、不重复。
建立 TCP 连接需要三次握手,这是面试高频考点:
- SYN:客户端发一个 SYN 包(seq=x),表示「我要连接」
- SYN-ACK:服务端回一个 SYN-ACK 包(seq=y, ack=x+1),表示「收到,我也准备好了」
- ACK:客户端再发一个 ACK 包(ack=y+1),表示「好,开始传数据吧」
🤔 面试常问:为什么是三次而不是两次?因为两次握手无法确认客户端的接收能力。如果客户端的旧 SYN 包延迟到达,服务端会误开连接浪费资源。三次握手确保双方的发送和接收能力都没问题。
关闭连接需要四次挥手:
- 客户端发 FIN,表示「我不发了」
- 服务端回 ACK,表示「收到」(此时服务端可能还有数据要发)
- 服务端发 FIN,表示「我也不发了」
- 客户端回 ACK,然后进入 TIME_WAIT 状态等待 2MSL
为什么是四次?因为 TCP 是全双工的,每个方向需要单独关闭。
- Sequence Number & ACK:每个字节都有序号,接收方确认收到
- Retransmission(重传):超时没收到 ACK 就重传
- Flow Control(流量控制):用 sliding window 控制发送速率
- Congestion Control(拥塞控制):慢启动、拥塞避免、快速重传、快速恢复
四、UDP vs TCP
UDP(User Datagram Protocol) 是无连接的、不可靠的传输协议。听起来好像很弱,但它有自己的优势:
- 没有握手和挥手,延迟更低
- 没有重传机制,适合实时场景(视频通话、游戏、DNS 查询)
- 头部开销小(8 字节 vs TCP 的 20+ 字节)
选择 TCP 还是 UDP 取决于你的场景:要可靠就用 TCP(HTTP、文件传输),要速度就用 UDP(实时音视频、IoT)。
五、应用层:HTTP 请求的一生
我们最常接触的应用层协议就是 HTTP。当你在浏览器输入一个 URL,背后发生了什么?
- DNS 解析:把域名(如 edryan.top)解析成 IP 地址
- TCP 三次握手:和服务器建立连接(HTTPS 还要 TLS 握手)
- 发送 HTTP 请求:GET /index.html HTTP/1.1
- 服务器处理并返回响应:HTTP/1.1 200 OK + HTML 内容
- 浏览器渲染:解析 HTML、CSS、JS,渲染页面
- TCP 四次挥手:关闭连接(或者 keep-alive 保持)
这个过程就是从应用层一路封装到网络接入层,经过路由器层层转发,到了服务器再解封装上去。
六、Python Socket 编程实战
说了这么多理论,不如动手写个代码。Python 的 socket 模块让我们可以直接操作传输层。下面是一个简单的 TCP echo server 和 client 的例子:
import socket
# 创建 TCP socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 绑定地址和端口
server.bind(('0.0.0.0', 9999))
server.listen(5)
print("Server listening on port 9999...")
while True:
# 等待客户端连接(三次握手在这里完成)
conn, addr = server.accept()
print(f"Connected by {addr}")
while True:
data = conn.recv(1024) # 接收数据
if not data:
break
print(f"Received: {data.decode()}")
conn.sendall(data) # 原样返回(echo)
conn.close() # 关闭连接(四次挥手)
print(f"Disconnected: {addr}")
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('127.0.0.1', 9999)) # 连接服务器(触发三次握手)
message = "Hello from TCP client!"
client.sendall(message.encode()) # 发送数据
print(f"Sent: {message}")
data = client.recv(1024) # 接收 echo
print(f"Received: {data.decode()}")
client.close() # 关闭连接
运行的时候先启动 server,再开 client。你会看到 server 收到消息后原样返回。在这个过程中,connect() 触发了三次握手,sendall() 的数据经过 TCP 分段、IP 封装、以太网帧封装后发送出去,close() 触发四次挥手。
import socket
# UDP Server
server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # SOCK_DGRAM = UDP
server.bind(('0.0.0.0', 8888))
print("UDP server listening on port 8888...")
while True:
data, addr = server.recvfrom(1024) # 无需 listen/accept,直接收
print(f"From {addr}: {data.decode()}")
server.sendto(data, addr) # 发送时需要指定目标地址
对比一下你会发现,UDP 的代码简单很多——没有 listen()、accept()、connect(),因为它不需要建立连接。这也对应了前面说的「无连接」特性。
七、常用网络调试工具
学网络不能光看理论,调试工具也得会用:
ping:测试主机之间的连通性,基于 ICMP 协议traceroute(Linux)/tracert(Windows):追踪数据包经过的路由路径netstat/ss:查看当前的网络连接和端口占用curl:发送 HTTP 请求,调试 APItcpdump/Wireshark:抓包分析,可以看到每一层的 header 信息
比如用 tcpdump 抓 TCP 三次握手:
sudo tcpdump -i eth0 -n 'tcp port 80' -c 6
你会看到 SYN、SYN-ACK、ACK 三个包,这就是我们前面讲的三次握手的真实体现。
八、总结
这篇文章我们过了一遍 TCP/IP 四层模型的核心概念:
- 四层模型:应用层 → 传输层 → 网络层 → 网络接入层
- IP 协议负责寻址和路由,不可靠但高效
- TCP 通过三次握手建立连接,通过序号、确认、重传等机制保证可靠性
- UDP 无连接、低延迟,适合实时场景
- HTTP 请求背后是 DNS + TCP 握手 + 请求/响应 + 挥手的完整流程
建议大家自己动手用 Python socket 写一写,再配合 tcpdump 抓包看看,比纯看书记得牢多了。网络协议这块内容很深,今天我们只是入门,后续可以继续聊 HTTPS/TLS、HTTP/2、WebSocket 等进阶话题。
参考资料:《计算机网络:自顶向下方法》、RFC 793(TCP)、RFC 791(IP)