TCP/IP 协议族
前言
在计算机网络中,操作系统之间的通信最终都要落到一套具体的协议之上,这套协议就是我们常说的 TCP/IP 协议族。
网上关于 TCP/IP 的资料很多,但如果缺少体系化的视角,很容易变成「记一堆名词,却不知道它们如何协同工作」。
本文尝试以「学习归纳」的方式,从整体到细节梳理 TCP/IP 协议族的核心概念和运行机制,帮助你建立起一个可反复回顾的知识框架,而不是零散记忆点。
一、TCP/IP 协议族概览
1.1 TCP/IP 是什么?
- 不是单一协议,而是一整套协议的集合
- IP:负责寻址和路由转发,是整个协议族的核心。
- TCP / UDP:负责端到端的传输。
- HTTP、DNS、SMTP、FTP 等:建立在 TCP 或 UDP 之上,面向应用。
- ARP、ICMP、DHCP、路由协议 等:为网络运行提供各种辅助功能。
- 设计目标
- 异构互联:不同厂商、不同操作系统、不同硬件架构,都可以通过统一协议互相通信。
- 可扩展性:从小型局域网扩展到互联网级别。
- 鲁棒性:在不可靠的底层物理网络上,构建尽量可靠的数据传输能力。
1.2 TCP/IP 与 OSI 模型
在学习网络时,常会遇到两个模型:
- OSI 七层模型(概念模型)
- 物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。
- TCP/IP 四层模型(工程实现中常用)
- 网络接口层、网络层、传输层、应用层。
两者的对应关系可以概括为:
- TCP/IP 的应用层 ≈ OSI 的 应用层 + 表示层 + 会话层。
- TCP/IP 的传输层 ≈ OSI 的传输层。
- TCP/IP 的网络层 ≈ OSI 的网络层。
- TCP/IP 的网络接口层 ≈ OSI 的数据链路层 + 物理层。
学习时可以用 OSI 帮助理解概念,但在具体协议和实现上,基本都以 TCP/IP 为主。
二、TCP/IP 四层模型总览
从上到下,TCP/IP 通常被划分为四层,每一层解决不同层次的问题:
2.1 应用层
- 作用:为具体应用提供网络功能接口,使应用程序不用直接处理底层细节。
- 常见协议
- HTTP / HTTPS:Web 浏览。
- FTP / SFTP:文件传输。
- SMTP / POP3 / IMAP:电子邮件。
- DNS:域名解析。
- SSH:安全远程登录。
程序员通常直接与这一层打交道,如浏览器、Web 服务、数据库客户端等。
2.2 传输层
- 作用:为应用层提供「端到端」的数据传输服务。
- 核心协议
- TCP(Transmission Control Protocol)
- 面向连接、可靠、有序、带流量控制和拥塞控制。
- 适用于对可靠性要求高的场景,如 Web、数据库、文件传输等。
- UDP(User Datagram Protocol)
- 无连接、不保证可靠、不保证顺序。
- 适用于实时性强、允许一定丢包的场景,如语音通话、视频直播、游戏等。
- TCP(Transmission Control Protocol)
2.3 网络层
- 作用:在不同网络之间转发数据,实现「端到端」的逻辑寻址和路由选择。
- 核心协议
- IP(Internet Protocol):IPv4、IPv6。
- ICMP:网络测试与错误报告(如
ping)。 - ARP / NDP:地址解析(IP ↔ MAC)。
- 各种 路由协议:RIP、OSPF、BGP 等。
2.4 网络接口层(数据链路 + 物理)
- 作用:与具体的物理网络打交道,将 IP 数据报封装为帧进行传输。
- 典型技术
- 以太网(Ethernet)、Wi-Fi、PPP 等。
- 交换机工作在数据链路层,以 MAC 地址为依据转发帧。
可以把这一层理解为:如何在「一跳之内」把比特送到下一台设备。
三、从应用到物理:数据如何在网络中传输?
理解「一条 HTTP 请求是如何在网络中完成一次来回」是学习 TCP/IP 的关键。
3.1 发送方向:一层层封装
以浏览器访问某个网站为例(简化流程):
- 应用层(HTTP)
- 浏览器构造 HTTP 请求报文(请求行、请求头、请求体)。
- 把这个报文交给传输层。
- 传输层(TCP)
- 为 HTTP 报文加上 TCP 头部,形成一个 TCP 段。
- 包含:源端口、目的端口、序列号、确认号、窗口大小等。
- 交给网络层。
- 为 HTTP 报文加上 TCP 头部,形成一个 TCP 段。
- 网络层(IP)
- 为 TCP 段加上 IP 头部,形成 IP 数据报。
- 包含:源 IP、目的 IP、TTL、协议号等。
- 根据路由表确定下一跳。
- 为 TCP 段加上 IP 头部,形成 IP 数据报。
- 网络接口层(以太网等)
- 在 IP 数据报外面加上 MAC 头部和尾部,形成 以太网帧。
- 包含:源 MAC、目的 MAC、类型、FCS 校验等。
- 通过网线或无线信号发送出去。
- 在 IP 数据报外面加上 MAC 头部和尾部,形成 以太网帧。
可以用一个简化的封装示意:
1
[ 以太网头 ][ IP 头 ][ TCP 头 ][ HTTP 数据 ][ 以太网尾 ]
3.2 接收方向:一层层解封装
对端接收到帧后,方向完全相反:
- 网卡收帧 → 网络接口层检查并去掉以太网头尾,交给 IP。
- IP 检查 IP 头,确认目的 IP、协议类型等。
- 如果是 TCP,交给 TCP 处理。
- TCP 根据端口号找到对应的应用进程,把 HTTP 数据交给应用层。
- Web 服务器解析 HTTP 请求,生成响应,再沿着同样的路径反方向送回。
关键理解:
- 每一层只关心自己的头部信息,对上层的内容一律视为「数据负载」。
- 整个过程可以抽象为:封装(往下走) / 解封装(往上走)。
四、地址与标识:IP、MAC、端口
在 TCP/IP 协议栈里,主机和应用的身份由不同层次的标识共同确定。
4.1 MAC 地址:链路层标识
- 位置:网卡上烧录的物理地址,通常写成 AA:BB:CC:DD:EE:FF。
- 作用:在同一个局域网中,识别具体的网络接口。
- 设备:交换机就是通过学习 MAC 地址表来转发帧的。
4.2 IP 地址:网络层标识
- 位置:由操作系统配置,可以通过 DHCP 自动获取,也可以手动配置。
- 作用:在跨网络的范围内,标识一台主机(或一个接口)的地址。
- 结构(IPv4)
- 32 位二进制,一般用点分十进制表示,例如 192.168.1.10。
- 配合 子网掩码 划分为「网络号 + 主机号」。
同一网段判断(简化):
- 对两台主机的 IP 分别与子网掩码做 AND 运算,得到各自的网络号。
- 如果网络号相同,则认为在同一子网,可以直接通信;否则需要通过路由器。
4.3 端口:传输层标识
- 作用:区分同一台主机上的不同应用进程。
- 范围:0–65535,其中 0–1023 为「知名端口」(如 80、443、22 等)。
- TCP/UDP 四元组
- 一条 TCP 连接可以用 源 IP、源端口、目的 IP、目的端口 唯一标识。
- 这也是网络抓包和排查问题时常用的定位方式。
4.4 ARP 与 DNS:两个重要的解析服务
- ARP(Address Resolution Protocol)
- 作用:在同一局域网中,已知对方 IP 时,解析出对方的 MAC 地址。
- 机制:广播 ARP 请求,然后目标主机单播 ARP 响应。
- DNS(Domain Name System)
- 作用:把人类易记的域名(例如 example.com)解析为 IP 地址。
- 常用 UDP 53 端口,也可以在某些情况下使用 TCP。
五、IP 协议与路由基础
5.1 IP 协议的核心特性
- 无连接:发送前不需要建立专门的「连接」,每个 IP 数据报独立发送。
- 尽力而为,不保证可靠
- 不保证一定送达,也不保证顺序。
- 不负责重传、流量控制等高级功能,这些由上层(如 TCP)完成。
5.2 子网与子网掩码
- 子网掩码 的作用是确定 IP 地址中哪一部分是「网络号」,哪一部分是「主机号」。
- 例如:
- IP:192.168.1.10
- 子网掩码:255.255.255.0
- 网络号:192.168.1.0,主机号:10。
掌握「IP + 子网掩码 → 网络号」的计算,对理解路由行为非常重要。
5.3 路由与默认网关
- 路由表:记录「目标网段 → 下一跳」的映射关系。
- 默认网关(Default Gateway):当目标不在本地子网时,本机会把 IP 数据报发给默认网关,由它继续转发。
一个简化的发送决策流程:
- 判断目标 IP 是否在本机子网内:
- 是:使用 ARP 获取对方 MAC,直接发送帧。
- 否:以默认网关为目标,发送帧给网关,由网关继续路由转发。
六、传输层:TCP 的可靠传输机制
TCP 是最常被详细考察的协议之一,但从学习角度看,有几个核心点要牢牢掌握:连接建立/释放、可靠性、流量控制和拥塞控制。
6.1 TCP 的主要特点
- 面向连接:通信前必须先建立连接(三次握手)。
- 可靠传输:
- 使用序列号(Sequence Number)和确认号(Acknowledgment Number)。
- 用超时重传机制处理丢包。
- 有序传输:接收方可以根据序列号对数据重新排序。
- 面向字节流:应用数据在 TCP 看起来是一条连续的字节流,而不是一个个独立报文。
- 流量控制和拥塞控制:通过窗口机制和相关算法控制发送速度。
6.2 三次握手:连接建立
简化过程如下(只看关键标志位):
- SYN:客户端 → 服务器
- 客户端发送一个 SYN 报文,表示希望建立连接,并携带初始序列号 seq = x。
- SYN + ACK:服务器 → 客户端
- 服务器收到后,如果同意连接,发送 SYN + ACK 报文,
- 自己的初始序列号 seq = y,同时确认号 ack = x + 1。
- ACK:客户端 → 服务器
- 客户端收到后,发送一个 ACK 报文,ack = y + 1。
- 至此,双方都确认了对方的收、发能力,连接建立完成。
从学习角度,关键是理解 「为什么需要三次」: 需要在不可靠网络上,让双方都确认对方具备收发能力,并完成初始序列号的同步。
6.3 四次挥手:连接释放
连接释放比建立要复杂一些,因为数据的发送和接收是双向的,每个方向都需要单独关闭。
简化流程如下:
- 第一次挥手:主动关闭方发送 FIN,表示「我这边的数据发完了」。
- 第二次挥手:被动关闭方回复 ACK,进入 CLOSE_WAIT 状态,此时可能还有数据要发送。
- 第三次挥手:被动关闭方发送自己的 FIN,表示「我也发完了」。
- 第四次挥手:主动关闭方回复 ACK,进入 TIME_WAIT 状态,等待一段时间(一般为 2 倍 MSL)后彻底关闭。
TIME_WAIT 的存在是为了解决「延迟的旧报文」和「对方最后 ACK 丢失」等问题,保证连接关闭的可靠性。
6.4 可靠性:确认和重传
- 确认机制:接收方通过 ACK 告诉发送方「哪些数据已经收到」。
- 超时重传:发送方在一定时间内没有收到 ACK,就认为报文丢失,会重传该报文。
- 序列号:确保数据在接收端可以按顺序重组。
在编程调试中,如果抓包工具中看到大量重传和乱序,很可能说明网络质量较差。
6.5 流量控制与拥塞控制(概念层面)
- 流量控制(Flow Control)
- 目标:避免发送方过快,导致接收方缓存被填满。
- 手段:利用 TCP 头部中的 窗口大小(Window Size) 字段,接收方根据自身缓冲能力动态调整。
- 拥塞控制(Congestion Control)
- 目标:防止过多数据注入到网络,使整个网络发生拥塞。
- 常见算法(只需在概念层面理解):
- 慢开始:一开始拥塞窗口很小,指数增长。
- 拥塞避免:达到一定阈值后改为线性增长。
- 快重传 / 快恢复:通过重复 ACK 快速发现丢包并适当减小窗口。
初学阶段不必死记算法细节,更重要的是理解:TCP 会根据网络反馈动态调整发送速度。
七、传输层:UDP 的简单与高效
7.1 UDP 的特点
- 无连接:发送数据前不需要建立连接,发送方直接把数据扔出去。
- 尽最大努力交付:不保证送达、不保证顺序、不做重传。
- 报文边界清晰:一发一收对应一个报文,应用层容易区分消息。
- 头部开销小:相比 TCP 更轻量,适合对实时性敏感、对丢包较为容忍的场景。
7.2 典型应用场景
- 实时音视频:如语音通话、直播、在线会议。
- 网络游戏:丢掉几个位置更新一般问题不大,延迟反而更加关键。
- DNS 查询:单次查询短小,重试成本低。
7.3 与 TCP 的对比(学习视角)
- 可靠性:TCP 有,UDP 没有。
- 建立连接:TCP 有握手,UDP 没有。
- 传输方式:TCP 面向字节流,UDP 面向报文。
- 应用层复杂度:
- 使用 TCP 时,可靠性由协议栈保证。
- 使用 UDP 时,如需可靠性,需要在应用层自己实现确认和重传逻辑。
理解这一点有助于在系统设计时选择合适的传输协议。
八、典型应用层协议与 TCP/IP 的关系
8.1 HTTP / HTTPS
- HTTP
- 构建在 TCP 之上(默认端口 80)。
- 无状态协议,结合 Cookie、Session 等实现会话管理。
- HTTPS
- 在 HTTP 与 TCP 之间加入了 TLS/SSL 安全层。
- 提供加密、完整性校验和身份认证(默认端口 443)。
8.2 DNS
- 多数情况下使用 UDP 53 端口。
- 当响应数据过大或进行区域传送时,会使用 TCP。
- 是访问互联网几乎所有服务的前置步骤。
8.3 其他常见协议
- SMTP / POP3 / IMAP:电子邮件传输与收取(基于 TCP)。
- FTP / SFTP:文件传输协议。
- SSH:安全远程登录,基于 TCP。
这些协议都建立在 TCP/IP 提供的基础通信能力之上,展现出「分层设计」的优势:上层专注业务语义,下层负责可靠传输。
Go代码示例
服务端 server.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package main
import (
"bufio"
"fmt"
"net"
)
func main() {
// 1. 监听指定地址和端口
listener, err := net.Listen("tcp", "127.0.0.1:8080")
if err != nil {
panic(err)
}
defer listener.Close()
fmt.Println("TCP 服务器启动,监听 127.0.0.1:8080 ...")
for {
// 2. 等待客户端连接
conn, err := listener.Accept()
if err != nil {
// 一般可以选择继续 Accept
fmt.Println("接受连接错误:", err)
continue
}
// 3. 为每个连接启动一个 goroutine 进行处理
go handleConn(conn)
}
}
// 处理单个客户端连接
func handleConn(conn net.Conn) {
defer conn.Close()
addr := conn.RemoteAddr().String()
fmt.Println("新连接:", addr)
reader := bufio.NewReader(conn)
for {
// 4. 按行读取客户端数据(以 '\n' 结尾)
line, err := reader.ReadString('\n')
if err != nil {
// 这里简单打印错误并退出
fmt.Println("连接关闭:", addr, "错误:", err)
return
}
fmt.Printf("收到来自 %s 的数据: %s", addr, line)
// 5. 将收到的数据原样回写给客户端(简单 Echo)
_, err = conn.Write([]byte("服务器收到: " + line))
if err != nil {
fmt.Println("发送数据给客户端失败:", err)
return
}
}
}
客户端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package main
import (
"bufio"
"fmt"
"net"
"os"
"strings"
)
func main() {
// 1. 连接到 TCP 服务器
conn, err := net.Dial("tcp", "127.0.0.1:8080")
if err != nil {
panic(err)
}
defer conn.Close()
fmt.Println("已连接到服务器 127.0.0.1:8080")
fmt.Println("请输入内容并回车,输入 exit 退出。")
// 从标准输入读取
stdinReader := bufio.NewReader(os.Stdin)
// 从连接读取
connReader := bufio.NewReader(conn)
for {
fmt.Print(">> ")
text, err := stdinReader.ReadString('\n')
if err != nil {
fmt.Println("读取输入失败:", err)
return
}
text = strings.TrimSpace(text)
if text == "exit" {
fmt.Println("退出客户端。")
return
}
// 2. 发送到服务器(加上换行符以便服务端按行读取)
_, err = conn.Write([]byte(text + "\n"))
if err != nil {
fmt.Println("发送数据失败:", err)
return
}
// 3. 读取服务器响应
reply, err := connReader.ReadString('\n')
if err != nil {
fmt.Println("读取服务器响应失败:", err)
return
}
fmt.Printf("服务器响应: %s", reply)
}
}
小结
TCP/IP 协议族为互联网提供了一个分层、可扩展、健壮的通信架构。
从上到下,它把复杂问题拆解为应用、传输、网络、链路多个层次,每一层关注不同的职责:
应用层关心业务语义,传输层负责端到端可靠或高效的传输,网络层解决跨网络的寻址与转发,网络接口层对接具体物理网络。
在学习时,一方面要掌握各层的关键协议和概念,另一方面更要通过抓包、命令行等方式观察真实网络行为,把「抽象的协议」变成「眼前可见的报文」。当你能顺畅地从一条 HTTP 请求一路追踪到以太网帧,并反推回来时,你对 TCP/IP 的理解就已经迈入了一个扎实的台阶。