计算机网络
尽量保证描写的清楚,且简洁。
TCP/IP 模型
四层:
- 应用层:
- HTTP、FTP、Telnet、DNS、SMTP
- 应用层是工作在操作系统中的用户态,传输层及以下则工作在内核态。
- 传输层:加上 TCP 头部
- TCP(大部分) 和 UDP
- TCP: 流量控制、超时重传、拥塞控制(保证数据包能可靠地传输给对方),当数据非常大:数据包大小超过 MSS(TCP 最大报文段长度),需要将数据包分块(TCP 段),这样丢包损失较小
- UDP:不保证数据包是否能抵达对方,但它实时性相对更好,传输效率也高
- 当设备作为接收方时,传输层则要负责把数据包传给应用,需要用一个编号将应用区分开来,即端口
- TCP(大部分) 和 UDP
- 网络层:(传输功能)加上 IP 头部
- IP:网络号+主机号(哪个子网+子网下的哪个主机)
- 将主机和子网掩码进行与运算,得到网络号,将主机和子网掩码取反值进行与运算得到主机号
- IP 协议的寻址作用是告诉我们去往下一个目的地该朝哪个方向走,路由则是根据「下一个目的地」选择路径。寻址更像在导航,路由更像在操作方向盘。
- IP:网络号+主机号(哪个子网+子网下的哪个主机)
- 网络接口层:加上 MAC 头部,并封装成数据帧(Data frame)发送到网络上
- 网络接口层主要为网络层提供「链路级别」传输的服务,负责在以太网、WiFi 这样的底层网络上发送原始数据包,工作在网卡这个层次,使用 MAC 地址来标识网络上的设备。
网络解析网址的方式 :
URL:
协议+//+服务器名称+/.../(数据源的路径)
通俗版解析:从输入网址到网页显示的全过程
1. 第一步:浏览器解析网址(找地址)
• 比喻:就像你想去朋友家,但只知道小区名,不知道具体门牌号。
• 过程:
• 拆解 URL:浏览器把网址拆成「域名」(如 www.example.com
)和「路径」(如 /index.html``)。 • **检查缓存**:先翻自己的「小本本」(浏览器缓存)看有没有记录过这个域名的 IP 地址。 • **问操作系统**:如果小本本没记,就问电脑管家(操作系统):“你记得
www.example.com` 的地址吗?”
2. DNS 查询:全网找门牌号
• 比喻:打电话问 114 查号台,但需要层层转接。
• 过程:
- 本地 DNS 服务器(小区物业):
◦ 先查自己的记录,没有就联系上级。 - 根 DNS 服务器(全球总台):
◦ 回答:“.com
的顶级 DNS 服务器地址是X.X.X.X,你问它。” - 顶级域 DNS(.com 管理局):
◦ 回答:“example.com
的权威 DNS 服务器是Y.Y.Y.Y,你问它。” - 权威 DNS 服务器(朋友小区的物业):
◦ 最终给出 IP 地址:“门牌号是93.184.216.34
!”
• 结果:浏览器拿到 IP 地址,准备出发。
3. 建立 TCP 连接:确认对方在家
• 比喻:打电话给朋友,先确认他是否在线。
• 三次握手:
- 你(客户端):“喂,能听到吗?”(发送
SYN
包) - 朋友(服务器):“能听到,你说话吧!”(回复
SYN-ACK
包) - 你:“好的,我要说正事了!”(发送
ACK
包)
• 结果:连接建立,开始传输数据。
4. 发送 HTTP 请求:打包你的需求
• 比喻:写一封信,告诉朋友你要借哪本书。
• 内容:
• 请求行:“GET /index.html HTTP/1.1”(我要首页)
• 请求头:附加信息(浏览器类型、支持的语言等)。
• 请求体:如果是登录请求,会包含账号密码。
5. 数据包旅行:跨城快递
• 比喻:把信交给快递员,经过多个中转站。
• 过程:
- 封装成 TCP 包:信纸装进信封(TCP 头部),写上序号(防止丢件)。
- 封装成 IP 包:套上快递袋(IP 头部),写清发件人(你的 IP)和收件人(服务器 IP)。
- MAC 地址定位:快递员(交换机)根据门牌号(MAC 地址)送到小区门口。
- 路由器接力:
◦ 小区门口快递站(路由器)检查地址:“这封信要跨省,先送到省中心!”
◦ 省中心再转发到目标城市,直到抵达朋友家。
6. 服务器处理:拆信并回信
• 比喻:朋友收到信,找到书后回寄给你。
• 过程:
• 拆包:服务器一层层剥开 IP、TCP 头部,看到 HTTP 请求。
• 处理请求:读取 /index.html
,从硬盘找到文件。
• 生成响应:把 HTML 内容塞进 HTTP 响应包,反向封装(TCP→IP→MAC)。
• 回传:按原路返回,经过路由器、交换机,最终到你的电脑。
7. 浏览器渲染:拆包裹拼图
• 比喻:收到回信后,把碎片拼成完整的画。
• 过程:
• 接收数据包:按 TCP 序号重组文件。
• 解析 HTML:读取文本、图片、CSS 样式。
• 渲染页面:把代码变成你看到的按钮、文字、图片。
关键概念通俗解析
术语 | 通俗解释 | 类比 |
---|---|---|
DNS | 把网站名翻译成数字地址的电话簿 | 查号台(114) |
TCP | 确保数据完整送达的“快递保价服务” | 快递员打电话确认你收到包裹 |
IP 地址 | 设备的全球唯一“门牌号” | 家庭住址(XX 省 XX 市 XX 街道) |
MAC 地址 | 设备的“身份证号”,用于同一网络内精准定位 | 快递柜编号(A 区 3 号柜) |
路由器 | 跨网络转发数据的“中转站” | 跨省快递分拣中心 |
交换机 | 同一网络内转发数据的“快递柜” | 小区内的快递代收点 |
Linux 网络包收发机制
一、网络模型基础
-
OSI 七层模型(理论模型):
• 应用层(用户接口)
• 表示层(数据格式转换)
• 会话层(建立/管理连接)
• 传输层(端到端传输)
• 网络层(路由和寻址)
• 数据链路层(物理寻址)
• 物理层(比特流传输) -
TCP/IP 四层模型(实际实现):
• 应用层(HTTP/FTP/DNS 等)
• 传输层(TCP/UDP)
• 网络层(IP/ICMP)
• 网络接口层(以太网/WiFi)
关键区别:TCP/IP 模型将 OSI 的上三层合并为应用层,更注重实用性。Linux 系统采用 TCP/IP 模型实现。
二、数据封装过程(发送时)
以发送"Hello"字符串为例:
应用层:原始数据 "Hello"
↓ 添加TCP头(源/目标端口、序列号等)
传输层:[TCP头]+"Hello"
↓ 添加IP头(源/目标IP地址)
网络层:[IP头]+[TCP头]+"Hello"
↓ 添加帧头帧尾(MAC地址、CRC校验)
网络接口层:[帧头]+[IP头]+[TCP头]+"Hello"+[帧尾]
三、接收网络包流程
-
硬件接收阶段:
• 网卡通过 DMA 将数据包存入环形缓冲区(Ring Buffer)
• 触发硬件中断通知 CPU -
中断处理优化(NAPI 机制):
• 传统方式:每个包都触发中断 → 高负载时 CPU 被频繁打断
• NAPI 方案:
◦ 首次中断唤醒处理线程
◦ 后续采用轮询方式批量处理多个数据包
◦ 减少中断次数,提升吞吐量 -
协议栈处理:
graph TD A[网卡驱动] --> B[网络接口层] B --> C{校验检查} C -->|合法| D[剥离帧头帧尾] D --> E[网络层处理IP头] E --> F[传输层处理TCP/UDP头] F --> G[Socket接收缓冲区] G --> H[应用层read调用]
-
关键数据结构:
•sk_buff
:贯穿整个协议栈的核心数据结构
• 通过指针调整实现零拷贝:struct sk_buff { unsigned char *head; // 缓冲区起始 unsigned char *data; // 当前协议层起始 unsigned char *tail; // 数据结束 unsigned char *end; // 缓冲区结束 };
四、发送网络包流程
-
应用层发起:
send(socket_fd, buffer, len, 0); // 系统调用
-
内核处理过程:
• 创建sk_buff
并拷贝用户数据
• 逐层添加协议头:graph LR A[应用数据] --> B[添加TCP头] B --> C[添加IP头] C --> D[添加帧头帧尾]
-
TCP 重传机制:
• 克隆sk_buff
副本发送
• 原始包保留直到收到 ACK
• 实现可靠传输的核心机制 -
分片处理(MTU 限制):
• 当 IP 包超过 1500 字节时:def fragment(packet): chunks = [] while len(packet) > MTU: chunk = packet[:MTU-20] # 保留IP头空间 chunks.append(add_ip_header(chunk)) packet = packet[MTU-20:] chunks.append(add_ip_header(packet)) return chunks
五、关键性能优化点
-
零拷贝技术:
• sendfile 系统调用:文件→Socket 直接传输
• 减少用户态与内核态数据拷贝 -
多队列网卡:
• 每个 CPU 核心绑定独立队列
• 避免缓存行竞争 -
TSO/GSO:
• TCP Segmentation Offload:网卡硬件分片
• Generic Segmentation Offload:内核延迟分片
六、完整流程对比
接收流程 | 发送流程 |
---|---|
1. 网卡 DMA 到 Ring Buffer | 1. 应用调用 send() |
2. 触发硬中断 | 2. 创建 sk_buff 并拷贝数据 |
3. ksoftirqd 软中断处理 | 3. 协议栈逐层封装 |
4. 协议栈逐层解析 | 4. 分片处理(如果需要) |
5. 数据存入 Socket 缓冲区 | 5. ARP 查询下一跳 MAC |
6. 应用 read()读取 | 6. 网卡 DMA 发送 |
七、常见问题解答
Q:为什么需要三次内存拷贝?
A:发送时的三次拷贝:
- 用户空间→内核 sk_buff
- TCP 重传保留副本
- IP 分片时产生新副本
Q:MTU 设置 1500 字节的历史原因?
A:源自早期以太网的电气特性限制,现代网络可通过 Jumbo Frame(9000 字节)提升吞吐量。
Q:如何查看协议栈统计?
netstat -s # 统计摘要
ethtool -S eth0 # 网卡详细统计
cat /proc/net/softnet_stat # 软中断统计