本质上就是Linux内核中的指针移动操作!!!!
struct sk_buffer {
struct sk_buffer* next; // 缓冲区链表指针
char* head; // 缓冲区头部指针
char* data; // 数据区起始指针
// 其他字段: truesize, len, mac_len等
}
假设UDP报头结构体为struct udp_head{......};
,简单演示提取过程:
((struct udp_head*)skb->head)->srcport = ntohs(xxx);
((struct udp_head*)skb->head)->destport = ntohs(yyyy);
Linux内核通过net_protocol
链表实现协议分用,IP层根据protocol
字段查找对应处理函数:
struct net_protocol {
int (*handler)(struct sk_buff *skb);
// 其他字段
};
+-+-----------------+-----------------+
| | 16位源端口 | 16位目的端口 |
+-----------------+-----------------+
| 32位序号 |
+---------------------------------------------------+
| 32位确认序号 |
+----------------+------+------+------+-----+----+------+----------------+
| 4位首部长度 | 保留6位 |U|A|P|R|S|F| 16位窗口大小 |
| (单位4字节) | |R|C|S|S|Y|I| |
| | |G|K|H|T|N|N| |
+----------------+------+------+------+-----+----+------+----------------+
| 16位检验和 | 16位紧急指针 |
+----------------+-------------------------------+
| 选项(可变长) |
+---------------------------------------------------+
| 数据区 |
+---------------------------------------------------+
首部长度值 × 4字节
= 实际首部字节数5 × 4 = 20字节
15 × 4 = 60字节
hlen = (tcp->data_offset & 0xF) << 2;
6位保留字段必须置0,为未来协议扩展预留空间
停等协议缺陷:每发送一个报文必须等待应答,信道利用率极低
TCP优化:引入滑动窗口实现批量发送+累计确认
假设:
确认序号=1
确认序号=1
(累计确认特性)确认序号=1
后,触发快重传D1客户端状态变迁:
CLOSED → SYN_SENT → ESTABLISHED → FIN_WAIT1 → FIN_WAIT2 → TIME_WAIT → CLOSED
服务器状态变迁:
CLOSED → LISTEN → SYN_RECV → ESTABLISHED → CLOSE_WAIT → LAST_ACK → CLOSED
1. 客户端 → 服务器: SYN, seq=1000, win=65535
2. 服务器 → 客户端: SYN, seq=2000, ack=1001, win=65535
3. 客户端 → 服务器: ACK, seq=1001, ack=2001, win=65535
+-------------------+-------------------+-------------------+
| 已确认数据区 | 滑动窗口区 | 待发送数据区 |
| [0, start) | [start, end] | [end+1, max] |
+-------------------+-------------------+-------------------+
^ ^ ^
| | |
已发送并确认 可发送未确认 未发送
RFC规范:不允许窗口左移(shrink window)
tcp_adjust_window
函数保证窗口单调不减慢启动(Slow Start):
拥塞避免(Congestion Avoidance):
快重传(Fast Retransmit):
快恢复(Fast Recovery):
# 查看当前拥塞控制算法
sysctl net.ipv4.tcp_congestion_control
# 常见算法:
# - reno: 标准TCP Reno
# - cubic: Linux默认算法,基于三次函数
# - bbr: 谷歌拥塞控制算法,基于带宽和RTT
特性 | TCP | UDP |
---|---|---|
连接管理 | 面向连接 | 无连接 |
可靠性 | 保证交付 | 不可靠交付 |
有序性 | 按序到达 | 可能乱序 |
流量控制 | 滑动窗口+拥塞控制 | 无 |
首部开销 | 20字节(标准) | 8字节 |
适用场景 | HTTP、FTP、邮件 | DNS、视频流、实时游戏 |
# 使用tcpdump抓取80端口TCP包
tcpdump -i eth0 port 80 -n -vv
# 使用Wireshark分析三次握手
1. 过滤条件:tcp.handshake.syn
2. 查看Seq/ACK序号变化
3. 分析窗口大小字段变化
# 查看TCP连接状态统计
netstat -nat | awk '{print $6}' | sort | uniq -c
# 查看详细连接信息
ss -antp | grep ESTABLISHED
# 跟踪TCP重传包
tcpdump -i eth0 "tcp[13] & 32 != 0"
# 修改TCP接收缓冲区大小
sysctl -w net.ipv4.tcp_rmem="4096 131072 6291456"
# 解释:最小值 默认值 最大值(6MB)
# 修改TCP发送缓冲区大小
sysctl -w net.ipv4.tcp_wmem="4096 16384 4194304"
# 调整TIME_WAIT回收策略
sysctl -w net.ipv4.tcp_tw_reuse=1 # 允许重用TIME_WAIT套接字
sysctl -w net.ipv4.tcp_tw_recycle=1 # 启用TIME_WAIT快速回收
# 扩大文件描述符限制
ulimit -n 65535
# 调整半连接队列大小
sysctl -w net.ipv4.tcp_max_syn_backlog=8192
# 优化SYN洪水防御
sysctl -w net.ipv4.tcp_syncookies=1
// 发送端
char buf[1024] = {0};
send(sockfd, buf, 1024, 0);
// 接收端
recv(sockfd, buf, 1024, 0);
// 发送端
uint32_t len = htonl(strlen(data));
send(sockfd, &len, 4, 0);
send(sockfd, data, strlen(data), 0);
// 接收端
uint32_t len;
recv(sockfd, &len, 4, 0);
len = ntohl(len);
char* buf = malloc(len);
recv(sockfd, buf, len, 0);
\r\n
作为报文分隔符(如HTTP协议)理解TCP协议的核心机制,不仅是网络编程的基础,更是理解互联网工作原理的关键。从指针操作到复杂的拥塞控制,每一个设计都蕴含着计算机网络领域的智慧结晶。