第三章 传输层 第五节 传输控制协议TCP
课程信息
- 课程名称: 计算机网络原理
- 授课教师: [教师姓名]
- 授课时间: [具体时间]
- 课时: 3学时
教学目标
知识目标
- 理解TCP协议的基本概念和特点
- 掌握TCP报文段的格式和字段含义
- 了解TCP连接建立和释放过程
- 掌握TCP的可靠传输机制
- 理解TCP的流量控制和拥塞控制
能力目标
- 能够分析TCP报文段的格式
- 能够理解TCP三次握手和四次挥手过程
- 能够进行简单的TCP编程
- 能够分析TCP性能问题
教学内容
一、TCP协议概述
1.1 什么是TCP
传输控制协议(Transmission Control Protocol,TCP) 是传输层的一个可靠协议,提供面向连接的、可靠的数据传输服务。
1.2 TCP在OSI模型中的位置
┌─────────────────────────────────────┐
│ 应用层 (Application) │ ← HTTP, FTP, SMTP, Telnet
├─────────────────────────────────────┤
│ 表示层 (Presentation) │
├─────────────────────────────────────┤
│ 会话层 (Session) │
├─────────────────────────────────────┤
│ 传输层 (Transport) │ ← TCP, UDP
├─────────────────────────────────────┤
│ 网络层 (Network) │ ← IP
├─────────────────────────────────────┤
│ 数据链路层 (Data Link) │
├─────────────────────────────────────┤
│ 物理层 (Physical) │
└─────────────────────────────────────┘
1.3 TCP的特点详解
特点 | 详细说明 | 影响 |
---|---|---|
面向连接 | 数据传输前需要建立连接 | 保证可靠性,增加延迟 |
可靠传输 | 保证数据能够到达目的地 | 需要确认和重传机制 |
有状态 | 维护连接状态信息 | 服务器资源消耗较大 |
全双工 | 支持双向数据传输 | 提高通信效率 |
字节流 | 将数据看作字节流 | 需要应用层处理消息边界 |
流量控制 | 控制发送速率 | 防止接收方溢出 |
拥塞控制 | 检测和避免网络拥塞 | 提高网络利用率 |
五、TCP流量控制
5.1 滑动窗口机制
滑动窗口示意图:
┌─────────────────────────────────────────────────────────────┐
│ 发送方滑动窗口 │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │已发送并确认│已发送未确认│可发送│不可发送 │ │
│ │ ┌─────┐ │ ┌─────┐ │┌───┐│ ┌─────────────────────┐ │ │
│ │ │1-100│ │ │101-200│ ││201││ │ 301-400 │ │ │
│ │ │ │ │ │ │ ││300││ │ │ │ │
│ │ └─────┘ │ └─────┘ │└───┘│ └─────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ↑ │
│ 发送窗口 │
└─────────────────────────────────────────────────────────────┘
接收方滑动窗口:
┌─────────────────────────────────────────────────────────────┐
│ ┌─────────────────────────────────────────────────────────┐ │
│ │已接收并确认│可接收│不可接收 │ │
│ │ ┌─────┐ │┌───┐│ ┌─────────────────────────────────┐ │ │
│ │ │1-200│ ││201││ │ 301-500 │ │ │
│ │ │ │ ││300││ │ │ │ │
│ │ └─────┘ │└───┘│ └─────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ↑ │
│ 接收窗口 │
└─────────────────────────────────────────────────────────────┘
5.2 窗口大小控制
窗口类型 | 说明 | 控制方式 |
---|---|---|
发送窗口 | 发送方可以发送的数据量 | 由接收方通告窗口大小决定 |
接收窗口 | 接收方可以接收的数据量 | 由接收缓冲区大小决定 |
拥塞窗口 | 网络允许的最大发送量 | 由拥塞控制算法决定 |
5.3 窗口滑动过程
窗口滑动示例:
初始状态:
发送窗口: [101-200] 可发送: [201-300]
接收窗口: [201-300]
步骤1: 发送数据201-250
发送窗口: [101-200][201-250] 可发送: [251-300]
接收窗口: [201-300] (等待数据)
步骤2: 收到ACK=201
发送窗口: [201-250] 可发送: [251-350] (窗口右移)
接收窗口: [251-350] (窗口右移)
步骤3: 收到ACK=251
发送窗口: [] 可发送: [251-400] (窗口继续右移)
接收窗口: [251-400]
5.4 零窗口问题
零窗口处理机制:
┌─────────────────────────────────────────────────────────────┐
│ 1. 接收方缓冲区满,通告窗口大小为0 │
│ 2. 发送方停止发送数据 │
│ 3. 发送方启动持续定时器 │
│ 4. 定时器超时,发送窗口探测报文 │
│ 5. 接收方回复当前窗口大小 │
│ 6. 如果窗口大小>0,恢复数据传输 │
│ 7. 如果窗口大小=0,重启持续定时器 │
└─────────────────────────────────────────────────────────────┘
5.5 糊涂窗口综合征
糊涂窗口综合征及解决方案:
┌─────────────────────────────────────────────────────────────┐
│ 问题描述: │
│ • 接收方每次只能接收很少数据 │
│ • 发送方每次只发送很少数据 │
│ • 导致网络效率低下 │
├─────────────────────────────────────────────────────────────┤
│ 接收方解决方案: │
│ • 延迟确认:等待缓冲区有足够空间再通告 │
│ • 最小窗口:只有窗口大小≥MSS时才通告非零窗口 │
├─────────────────────────────────────────────────────────────┤
│ 发送方解决方案: │
│ • Nagle算法:延迟发送小数据包 │
│ • 只有满足以下条件之一才发送: │
│ - 数据长度≥MSS │
│ - 收到所有已发送数据的确认 │
│ - 强制发送标志(PSH) │
└─────────────────────────────────────────────────────────────┘
六、TCP拥塞控制
6.1 拥塞控制概述
拥塞控制目标:
┌─────────────────────────────────────────────────────────────┐
│ • 防止网络拥塞 │
│ • 提高网络利用率 │
│ • 保证网络公平性 │
│ • 适应网络动态变化 │
└─────────────────────────────────────────────────────────────┘
6.2 拥塞控制算法
算法阶段 | 说明 | 窗口变化 | 触发条件 |
---|---|---|---|
慢启动 | 指数增长探测网络容量 | cwnd × 2 | 连接开始或超时 |
拥塞避免 | 线性增长避免拥塞 | cwnd + 1 | cwnd ≥ ssthresh |
快速重传 | 立即重传丢失数据 | 不变 | 收到3个重复ACK |
快速恢复 | 快速恢复到拥塞避免 | cwnd = ssthresh | 快速重传后 |
6.3 慢启动算法
慢启动过程示意图:
时间 →
┌─────────────────────────────────────────────────────────────┐
│ cwnd │
│ ↑ ● │
│ 16│ ● │ │
│ │ ● │ │
│ 12│ ● │ │
│ │ ● │ │
│ 8│ ● │ │
│ │ ● │ │
│ 4│ ● │ │
│ │ ● │ │
│ 2│ ● │ │
│ │ ● │ │
│ 1│ ●─────────●─────────────────────┼───────────────────────│
│ └─────────────────────────────────┼───────────────────────│
│ 1 2 3 4 5 6 7 8 │ RTT │
│ │ │
│ ssthresh = 8 │
│ 转入拥塞避免 │
└─────────────────────────────────────────────────────────────┘
算法描述:
1. 初始 cwnd = 1 MSS
2. 每收到一个ACK,cwnd += 1
3. 实际效果:每个RTT,cwnd翻倍
4. 当 cwnd ≥ ssthresh 时,转入拥塞避免
6.4 拥塞避免算法
拥塞避免过程示意图:
cwnd
↑
16│ ●
│ ● │
14│ ● │
│ ● │
12│ ● │
│ ● │
10│ ● │
│ ● │
8│●─────────●─────────────────┼───────────────────────────────
│ │
6│ │
│ │
4│ │
│ │
2│ │
│ │
0└───────────────────────────┼───────────────────────────────
1 2 3 4 5 6 │ RTT
│
ssthresh = 8
算法描述:
1. 当 cwnd ≥ ssthresh 时启动
2. 每收到一个ACK,cwnd += 1/cwnd
3. 实际效果:每个RTT,cwnd += 1
4. 线性增长,谨慎探测网络容量
6.5 快速重传和快速恢复
快速重传和快速恢复示意图:
┌─────────────────────────────────────────────────────────────┐
│ 发送方:1 2 3 4 5 6 7 8 9 10 │
│ 接收方:1 2 X 4 5 6 7 8 9 10 (丢失3) │
│ 确认: 2 3 3 3 3 3 3 3 3 3 (重复ACK=3) │
│ ↑ │
│ 收到3个重复ACK │
│ ↓ │
│ 立即重传数据段3 │
│ ↓ │
│ 进入快速恢复状态 │
└─────────────────────────────────────────────────────────────┘
算法流程:
1. 收到3个重复ACK
2. ssthresh = cwnd / 2
3. 重传丢失的数据段
4. cwnd = ssthresh + 3
5. 每收到一个重复ACK,cwnd += 1
6. 收到新ACK时,cwnd = ssthresh
7. 进入拥塞避免阶段
6.6 超时重传处理
超时重传的拥塞控制:
┌─────────────────────────────────────────────────────────────┐
│ cwnd │
│ ↑ │
│ 16│ ● │
│ │ ● ● │
│ 12│ ● ● │
│ │ ● ● │
│ 8│ ● ● │
│ │ ● ● │
│ 4│ ● ● │
│ │ ● ● │
│ 2│ ● ● │
│ │ ● ● │
│ 1│ ● ●───────────────│
│ └─────────────┬─────────────────────────────────────────│
│ │ │
│ 超时重传 │
│ ssthresh = cwnd/2 │
│ cwnd = 1 │
│ 重新慢启动 │
└─────────────────────────────────────────────────────────────┘
处理步骤:
1. 检测到超时
2. ssthresh = max(cwnd/2, 2)
3. cwnd = 1
4. 重传超时的数据段
5. 进入慢启动阶段
七、TCP编程基础
7.1 TCP Socket编程流程
TCP编程流程图:
┌─────────────────────────────────────────────────────────────┐
│ 服务器端 │
│ ┌─────────┬─────────┬─────────┬─────────┬─────────┬──────┐ │
│ │ socket()│ bind() │listen() │accept() │ recv() │close()│ │
│ │ 创建套接字│ 绑定地址 │ 监听连接 │ 接受连接 │ 接收数据 │ 关闭 │ │
│ └─────────┴─────────┴─────────┴─────────┴─────────┴──────┘ │
└─────────────────────────────────────────────────────────────┘
│
│ 三次握手
▼
┌─────────────────────────────────────────────────────────────┐
│ 客户端 │
│ ┌─────────┬─────────┬─────────┬─────────┬─────────────────┐ │
│ │ socket()│connect()│ send() │ recv() │ close() │ │
│ │ 创建套接字│ 连接服务器│ 发送数据 │ 接收数据 │ 关闭连接 │ │
│ └─────────┴─────────┴─────────┴─────────┴─────────────────┘ │
└─────────────────────────────────────────────────────────────┘
7.2 TCP服务器端代码示例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#define PORT 8080
#define BUFFER_SIZE 1024
#define MAX_CLIENTS 5
int main() {
int server_fd, client_fd;
struct sockaddr_in server_addr, client_addr;
char buffer[BUFFER_SIZE];
socklen_t client_len = sizeof(client_addr);
// 1. 创建TCP套接字
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd < 0) {
perror("Socket creation failed");
exit(EXIT_FAILURE);
}
// 2. 设置套接字选项
int opt = 1;
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR,
&opt, sizeof(opt)) < 0) {
perror("Setsockopt failed");
exit(EXIT_FAILURE);
}
// 3. 设置服务器地址
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(PORT);
// 4. 绑定地址
if (bind(server_fd, (struct sockaddr*)&server_addr,
sizeof(server_addr)) < 0) {
perror("Bind failed");
exit(EXIT_FAILURE);
}
// 5. 监听连接
if (listen(server_fd, MAX_CLIENTS) < 0) {
perror("Listen failed");
exit(EXIT_FAILURE);
}
printf("TCP服务器启动,监听端口 %d\n", PORT);
// 6. 接受连接和处理数据
while (1) {
// 接受客户端连接
client_fd = accept(server_fd,
(struct sockaddr*)&client_addr,
&client_len);
if (client_fd < 0) {
perror("Accept failed");
continue;
}
printf("客户端连接:%s:%d\n",
inet_ntoa(client_addr.sin_addr),
ntohs(client_addr.sin_port));
// 接收和发送数据
while (1) {
int bytes_read = recv(client_fd, buffer, BUFFER_SIZE, 0);
if (bytes_read <= 0) {
printf("客户端断开连接\n");
break;
}
buffer[bytes_read] = '\0';
printf("收到消息: %s\n", buffer);
// 回显数据
send(client_fd, buffer, bytes_read, 0);
}
close(client_fd);
}
close(server_fd);
return 0;
}
7.3 TCP客户端代码示例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 8080
#define BUFFER_SIZE 1024
int main() {
int client_fd;
struct sockaddr_in server_addr;
char buffer[BUFFER_SIZE];
char message[BUFFER_SIZE];
// 1. 创建TCP套接字
client_fd = socket(AF_INET, SOCK_STREAM, 0);
if (client_fd < 0) {
perror("Socket creation failed");
exit(EXIT_FAILURE);
}
// 2. 设置服务器地址
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SERVER_PORT);
server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
// 3. 连接服务器
if (connect(client_fd, (struct sockaddr*)&server_addr,
sizeof(server_addr)) < 0) {
perror("Connection failed");
exit(EXIT_FAILURE);
}
printf("已连接到服务器 %s:%d\n", SERVER_IP, SERVER_PORT);
printf("输入消息 (输入 'quit' 退出):\n");
// 4. 发送和接收数据
while (1) {
printf("> ");
fgets(message, BUFFER_SIZE, stdin);
// 去除换行符
message[strcspn(message, "\n")] = 0;
// 检查退出条件
if (strcmp(message, "quit") == 0) {
break;
}
// 发送数据
if (send(client_fd, message, strlen(message), 0) < 0) {
perror("Send failed");
break;
}
// 接收回复
int bytes_read = recv(client_fd, buffer, BUFFER_SIZE, 0);
if (bytes_read <= 0) {
printf("服务器断开连接\n");
break;
}
buffer[bytes_read] = '\0';
printf("服务器回复: %s\n", buffer);
}
close(client_fd);
printf("连接已关闭\n");
return 0;
}
7.4 TCP编程关键函数
函数 | 功能 | 参数说明 | 返回值 |
---|---|---|---|
socket() | 创建套接字 | AF_INET, SOCK_STREAM, 0 | 套接字描述符 |
bind() | 绑定地址 | sockfd, sockaddr, addrlen | 0成功,-1失败 |
listen() | 监听连接 | sockfd, backlog | 0成功,-1失败 |
accept() | 接受连接 | sockfd, sockaddr, addrlen | 新套接字描述符 |
connect() | 连接服务器 | sockfd, sockaddr, addrlen | 0成功,-1失败 |
send() | 发送数据 | sockfd, buffer, len, flags | 发送字节数 |
recv() | 接收数据 | sockfd, buffer, len, flags | 接收字节数 |
close() | 关闭套接字 | sockfd | 0成功,-1失败 |
7.5 TCP编程注意事项
TCP编程注意事项:
┌─────────────────────────────────────────────────────────────┐
│ 连接管理 │
│ • 正确处理三次握手和四次挥手 │
│ • 设置适当的超时时间 │
│ • 处理连接异常中断 │
├─────────────────────────────────────────────────────────────┤
│ 数据传输 │
│ • TCP是字节流,需要处理消息边界 │
│ • 检查send()和recv()的返回值 │
│ • 处理部分发送和接收 │
├─────────────────────────────────────────────────────────────┤
│ 错误处理 │
│ • 检查所有系统调用的返回值 │
│ • 正确处理SIGPIPE信号 │
│ • 实现重连机制(如需要) │
├─────────────────────────────────────────────────────────────┤
│ 性能优化 │
│ • 使用适当的缓冲区大小 │
│ • 考虑使用非阻塞I/O或多路复用 │
│ • 设置TCP_NODELAY选项(如需要) │
└─────────────────────────────────────────────────────────────┘
八、TCP性能分析
8.1 TCP性能指标
指标 | 说明 | 影响因素 |
---|---|---|
吞吐量 | 单位时间传输的数据量 | 带宽、窗口大小、RTT |
延迟 | 数据传输的时间 | RTT、处理时间 |
连接建立时间 | 三次握手完成时间 | RTT、网络状况 |
CPU使用率 | 协议处理占用的CPU | 数据量、连接数 |
8.2 TCP性能优化
TCP性能优化策略:
┌─────────────────────────────────────────────────────────────┐
│ 网络层优化 │
│ • 增加带宽 │
│ • 减少网络延迟 │
│ • 优化路由路径 │
├─────────────────────────────────────────────────────────────┤
│ 协议层优化 │
│ • 调整窗口大小 │
│ • 启用窗口缩放 │
│ • 使用选择性确认(SACK) │
│ • 调整拥塞控制算法 │
├─────────────────────────────────────────────────────────────┤
│ 应用层优化 │
│ • 减少连接数 │
│ • 使用连接池 │
│ • 批量传输数据 │
│ • 数据压缩 │
├─────────────────────────────────────────────────────────────┤
│ 系统层优化 │
│ • 调整内核参数 │
│ • 增加缓冲区大小 │
│ • 使用高效的I/O模型 │
└─────────────────────────────────────────────────────────────┘
课堂练习
练习1:TCP报文段分析
1.1 报文段结构分析
给定一个TCP报文段的十六进制表示:
TCP头部: 1F 90 00 50 00 00 10 00 00 00 10 01 50 18 20 00
A1 B2 00 00 01 01 08 0A 00 12 34 56 00 12 34 5A
数据: 48 65 6C 6C 6F 20 57 6F 72 6C 64
字段 | 值 | 计算过程 |
---|---|---|
源端口 | 8080 | 0x1F90 = 31×256 + 144 = 8080 |
目标端口 | 80 | 0x0050 = 80 |
序列号 | 4096 | 0x00001000 = 4096 |
确认号 | 4097 | 0x00001001 = 4097 |
控制位 | PSH+ACK | 0x18 = 00011000 |
窗口大小 | 8192 | 0x2000 = 8192 |
练习2:三次握手分析
三次握手过程分析:
时间 客户端状态 服务器状态 报文段
t0 CLOSED LISTEN -
t1 SYN_SENT LISTEN SYN, seq=1000
t2 SYN_SENT SYN_RCVD SYN+ACK, seq=2000, ack=1001
t3 ESTABLISHED SYN_RCVD ACK, seq=1001, ack=2001
t4 ESTABLISHED ESTABLISHED -
练习3:滑动窗口计算
滑动窗口练习:
初始条件:
- 发送窗口大小:1000字节
- 已发送序号:1-500
- 已确认序号:1-300
- 接收窗口大小:800字节
问题:
1. 当前可发送数据量?
答案:500字节 (1000-500)
2. 收到ACK=401后,可发送数据量?
答案:600字节 (1000-400)
3. 如果接收方通告窗口大小为600,实际发送窗口?
答案:600字节 (min(发送窗口, 通告窗口))
课后作业
作业1:理论分析题
1.1 TCP与UDP详细对比
制作TCP与UDP的详细对比表,包括:
- 连接管理
- 可靠性机制
- 流量控制
- 拥塞控制
- 应用场景
- 性能特点
1.2 TCP拥塞控制算法分析
详细分析TCP拥塞控制的四个阶段:
- 慢启动
- 拥塞避免
- 快速重传
- 快速恢复
绘制拥塞窗口变化图,说明各阶段的触发条件和窗口调整策略。
作业2:实践编程题
2.1 多线程TCP服务器
实现一个支持多客户端并发连接的TCP服务器:
- 使用多线程处理客户端连接
- 实现简单的聊天室功能
- 支持客户端列表管理
- 实现优雅关闭
2.2 HTTP客户端实现
使用TCP套接字实现简单的HTTP客户端:
- 支持GET和POST请求
- 解析HTTP响应头
- 支持重定向
- 实现连接复用
作业3:性能测试题
3.1 TCP性能测试
编写程序测试TCP性能:
- 测试不同数据包大小的吞吐量
- 测试不同并发连接数的性能
- 分析TCP参数对性能的影响
- 生成性能测试报告
3.2 网络抓包分析
使用Wireshark分析TCP连接:
- 抓取完整的TCP连接过程
- 分析三次握手和四次挥手
- 观察滑动窗口变化
- 分析拥塞控制行为
参考资料
主要教材
- 《计算机网络原理》 李全龙编著 - 2018年版
- 《计算机网络》 谢希仁编著 - 第8版
- 《TCP/IP详解 卷1:协议》 W. Richard Stevens 著
技术标准
- RFC 793 - Transmission Control Protocol (TCP)
- RFC 1122 - Requirements for Internet Hosts -- Communication Layers
- RFC 2581 - TCP Congestion Control
- RFC 3168 - The Addition of Explicit Congestion Notification (ECN) to IP
实践工具
- Wireshark - 网络协议分析工具
- iperf3 - 网络性能测试工具
- netstat - 网络连接状态查看工具
- ss - 现代网络统计工具
在线资源
- TCP/IP指南 - http://www.tcpipguide.com/
- RFC文档库 - https://tools.ietf.org/rfc/
- Linux网络编程 - https://man7.org/linux/man-pages/
板书设计
主板书结构
TCP协议详解
┌─────────────────────────────────────────────────────────────┐
│ 一、协议特点 │
│ ┌─────────┬─────────┬─────────┬─────────┬─────────────────┐ │
│ │面向连接 │ 可靠传输 │ 全双工 │ 字节流 │ 流量/拥塞控制 │ │
│ │(三次握手)│(确认重传)│(双向) │(无边界) │ (窗口/算法) │ │
│ └─────────┴─────────┴─────────┴─────────┴─────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ 二、连接管理 │
│ ┌─────────────────┬─────────────────┬─────────────────────┐ │
│ │ 三次握手 │ 数据传输 │ 四次挥手 │ │
│ │ SYN→SYN+ACK→ACK │ 数据+确认 │ FIN→ACK→FIN→ACK │ │
│ └─────────────────┴─────────────────┴─────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ 三、可靠传输 │
│ ┌─────────┬─────────┬─────────┬─────────┬─────────────────┐ │
│ │ 序列号 │ 确认号 │ 重传 │ 校验和 │ 滑动窗口 │ │
│ │(排序) │(确认) │(可靠) │(检错) │ (流量控制) │ │
│ └─────────┴─────────┴─────────┴─────────┴─────────────────┘ │
└─────────────────────────────────────────────────────────────┘
重点强调
重点概念:
• TCP是面向连接的可靠传输协议
• 三次握手建立连接,四次挥手释放连接
• 滑动窗口实现流量控制
• 拥塞控制维护网络稳定
关键机制:
• 序列号和确认号保证数据顺序
• 超时重传和快速重传保证可靠性
• 慢启动和拥塞避免控制网络拥塞
常见应用:
• HTTP/HTTPS (80/443端口) - 网页浏览
• FTP (20/21端口) - 文件传输
• SMTP (25端口) - 邮件发送
• SSH (22端口) - 安全远程登录
讲义编写时间:2024年12月
课程进度:已完成传输层TCP协议详解
下次课预告:第四章 网络层 IP协议
评论0
暂时没有评论