tcp/ip技术概述
1 tcp/ip技术由来
1.1 从ARPANET到Internet
诞生背景:
- 1969年,ARPANET最初使用NCP(Network Control Protocol)
- 随着网络规模扩大,NCP的局限性凸显
- 需要一种能够连接异构网络的通用协议
1.2 为什么叫TCP/IP?
TCP/IP实际上是一个协议族,以两个核心协议命名:
- TCP(传输控制协议):负责可靠传输
- IP(网际协议):负责路由寻址
1.3 TCP/IP设计哲学
TCP/IP的设计体现了几个关键思想: 🎯 核心设计原则:
- 端到端原则:智能在端点,网络核心保持简单
- 鲁棒性:网络故障时能自动恢复
- 无状态设计:网络层不保存连接状态
- 分层抽象:各层独立演进
经典名言:
"IP over everything, everything over IP"
— 让IP运行在任何网络上,任何应用都运行在IP上
1.4 OSI模型与TCP/IP的对比
| 特性 | OSI七层模型 | TCP/IP四层模型 |
|---|---|---|
| 提出时间 | 1984年 | 1974年 |
| 层次数量 | 7层 | 4层 |
| 复杂性 | 理论完善,实现复杂 | 实用主义,简洁高效 |
| 市场接受度 | 教学参考 | 实际工业标准 |
2 tcp/ip技术应用
2.1 互联网时代的基石
无处不在的TCP/IP:
2.2 日常生活中的应用场景
🌐 Web浏览
- HTTP/HTTPS协议基于TCP
- 每次打开网页都在使用TCP/IP
- 示例:浏览器输入URL到页面显示的全过程
📧 电子邮件
- SMTP发送邮件
- POP3/IMAP接收邮件
- 附件传输的可靠保证
🎥 视频流媒体
- YouTube、Netflix使用TCP(或QUIC)
- 直播使用UDP降低延迟
- 自适应码率技术
2.3 企业级应用
| 应用领域 | 典型场景 | 使用的协议 |
|---|---|---|
| 数据中心 | 服务器集群通信 | TCP/UDP |
| 金融交易 | 高频交易 | 定制UDP |
| 工业控制 | PLC通信 | TCP/Modbus |
| 医疗设备 | DICOM影像传输 | TCP |
| 军事通信 | 战场数据链 | 定制IP |
2.4 新兴领域的应用
📱 移动互联网
- 4G/5G核心网基于IP
- 移动APP都使用TCP/UDP
- MQTT用于物联网推送
🏠 物联网
轻量级协议栈:
- CoAP:类似HTTP的轻量协议
- MQTT:发布订阅模式
- LwIP:嵌入式TCP/IP实现
- uIP:极简TCP/IP栈
☁️ 云计算
- 虚拟机网络:VXLAN over IP
- 容器网络:Overlay网络
- 服务网格:Sidecar代理
2.5 网络故障排查中的应用
常用工具:
bash
# ping:测试网络连通性
ping google.com
# traceroute:跟踪路由路径
traceroute google.com
# netstat:查看网络连接
netstat -an | grep 80
# tcpdump:抓包分析
tcpdump -i eth0 tcp port 80
# telnet:测试端口连通性
telnet server.com 80
典型问题排查流程:
3 tcp/ip的实现
3.1 协议栈的软件架构
TCP/IP协议栈的实现方式主要有三种:
| 实现方式 | 代表 | 特点 | 适用场景 |
|---|---|---|---|
| 内核态协议栈 | Linux内核 | 性能高,与操作系统紧密结合 | 服务器、PC |
| 用户态协议栈 | DPDK, Netmap | 零拷贝,可定制,性能极致 | 高性能网络、NFV |
| 轻量级协议栈 | lwIP, uIP | 资源占用小,可移植性强 | 嵌入式设备、RTOS |
Linux 内核实现
3.2 核心数据结构的实现
3.2.1 TCP控制块 (TCP Control Block)
以Linux内核为例,TCP控制块是连接的核心数据结构: c
// include/net/tcp.h (简化版)
struct tcp_sock {
/* 继承的INET sock结构 */
struct inet_connection_sock inet_conn;
/* 发送相关 */
u32 snd_nxt; /* 下一个要发送的序号 */
u32 snd_una; /* 第一个未确认的序号 */
u32 snd_cwnd; /* 拥塞窗口 */
u32 snd_ssthresh; /* 慢启动阈值 */
/* 接收相关 */
u32 rcv_nxt; /* 下一个期望接收的序号 */
u32 rcv_wnd; /* 接收窗口大小 */
/* 时间相关 */
u32 srtt; /* 平滑后的RTT */
u32 mdev; /* RTT的平均偏差 */
/* 队列管理 */
struct sk_buff_head out_of_order_queue; /* 乱序队列 */
struct sk_buff_head write_queue; /* 发送队列 */
};
在lwIP中的简化实现:
// lwip/include/lwip/tcp.h
struct tcp_pcb {
/* IP和端口 */
ip_addr_t local_ip;
u16_t local_port;
ip_addr_t remote_ip;
u16_t remote_port;
/* 状态 */
u8_t state; /* TCP状态:CLOSED, LISTEN, ESTABLISHED等 */
/* 序列号 */
u32_t rcv_nxt;
u32_t snd_nxt;
u32_t snd_una;
/* 窗口 */
u16_t rcv_wnd;
u16_t snd_wnd;
/* 回调函数 - 事件驱动核心 */
err_t (*recv)(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);
err_t (*sent)(void *arg, struct tcp_pcb *pcb, u16_t space);
void (*errf)(void *arg, err_t err);
/* 队列 */
struct tcp_seg *unsent; /* 未发送队列 */
struct tcp_seg *unacked; /* 未确认队列 */
struct tcp_seg *ooseq; /* 乱序队列 */
};
3.2.2 数据包缓冲区 (sk_buff/pbuf)
Linux sk_buff结构: c
struct sk_buff {
/* 链表管理 */
struct sk_buff *next;
struct sk_buff *prev;
/* 时间戳 */
ktime_t tstamp;
/* 网络设备 */
struct net_device *dev;
/* 指针管理 - 零拷贝关键 */
unsigned char *head; /* 缓冲区头部 */
unsigned char *data; /* 数据头部 */
unsigned char *tail; /* 数据尾部 */
unsigned char *end; /* 缓冲区尾部 */
/* 长度信息 */
unsigned int len; /* 实际数据长度 */
unsigned int data_len; /* 数据分片长度 */
/* 各层头部指针 - 避免重复解析 */
union {
struct tcphdr *th;
struct udphdr *uh;
struct iphdr *iph;
};
};
lwIP pbuf结构(轻量级设计): c
struct pbuf {
struct pbuf *next; /* 下一个pbuf(链表结构) */
void *payload; /* 数据指针 */
u16_t tot_len; /* 总长度(所有pbuf之和) */
u16_t len; /* 当前pbuf长度 */
u8_t type; /* PBUF_RAM, PBUF_ROM, PBUF_REF等 */
u8_t flags; /* 标志位 */
u16_t ref; /* 引用计数(零拷贝关键) */
};
3.3 数据接收路径的实现
3.3.1 Linux内核接收路径
关键函数调用链:
c
// 网卡中断处理
igb_poll() → napi_complete() → netif_receive_skb()
// 协议栈处理
netif_receive_skb() → ip_rcv() → ip_local_deliver() → tcp_v4_rcv()
// TCP核心处理
tcp_v4_rcv() → tcp_input() → tcp_rcv_established() → tcp_data_queue()
// 数据交付
tcp_data_queue() → skb_queue_tail(&sk->sk_receive_queue, skb) →
sk->sk_data_ready(sk) → sock_def_readable() → wake_up_interruptible()
3.3.2 lwIP的事件驱动实现
lwIP采用回调机制,更适合嵌入式系统: c
// tcp_input主函数流程(简化版)
void tcp_input(struct pbuf *p, struct netif *inp)
{
struct tcp_pcb *pcb;
struct tcp_hdr *tcphdr;
// 1. 基本检查(校验和、长度)
tcphdr = (struct tcp_hdr *)p->payload;
if (inet_chksum_pseudo(p, ...) != 0) {
pbuf_free(p);
return;
}
// 2. 查找对应的PCB
pcb = tcp_lookup(p);
if (pcb == NULL) {
tcp_rst(...); // 发送RST
pbuf_free(p);
return;
}
// 3. TCP状态机处理
tcp_process(pcb);
// 4. 数据接收 - 直接回调应用层
if (pcb->recv != NULL && recv_data != NULL) {
pcb->recv(pcb->callback_arg, pcb, recv_data, ERR_OK);
}
// 5. 发送响应
tcp_output(pcb);
}
3.4 关键算法的实现
3.4.1 滑动窗口的实现
c
// 发送窗口可用空间计算
static inline u16_t tcp_sndbuf(struct tcp_pcb *pcb)
{
// snd_una: 第一个未确认序号
// snd_nxt: 下一个要发送序号
// snd_wnd: 对方接收窗口
u32_t unused = pcb->snd_una + pcb->snd_wnd - pcb->snd_nxt;
if (unused > 0xffff)
return 0xffff; // 窗口最大65535
if (unused > 0)
return (u16_t)unused;
return 0; // 窗口已满
}
// 接收窗口更新
void tcp_recved(struct tcp_pcb *pcb, u16_t len)
{
// 应用层已消费len字节数据
pcb->rcv_wnd += len;
// 如果窗口扩大超过阈值,发送窗口更新
if (pcb->rcv_wnd > pcb->rcv_ann_wnd + TCP_WND_UPDATE_THRESHOLD) {
pcb->rcv_ann_wnd = pcb->rcv_wnd;
tcp_output(pcb); // 立即发送ACK更新窗口
}
}
3.4.2 超时重传的实现
RTT估算算法:
// 计算平滑RTT (RFC 6298)
static void tcp_rtt_estimator(struct tcp_sock *tp, u32_t mrtt)
{
long m = mrtt; // 测量到的RTT
if (tp->srtt == 0) {
// 首次测量
tp->srtt = m << 3; // srtt = m * 8
tp->mdev = m << 1; // mdev = m * 2
} else {
// 平滑更新
m -= (tp->srtt >> 3); // 差值
tp->srtt += m; // 更新srtt
if (m < 0)
m = -m;
m -= (tp->mdev >> 2); // 更新偏差
tp->mdev += m;
}
// 计算RTO(重传超时时间)
tp->rto = (tp->srtt >> 3) + tp->mdev;
}
3.4.3 拥塞控制的实现
Linux中的CUBIC算法核心:
// net/ipv4/tcp_cubic.c (简化版)
static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 in_flight)
{
struct tcp_sock *tp = tcp_sk(sk);
struct bictcp *ca = inet_csk_ca(sk);
if (tp->snd_cwnd <= tp->snd_ssthresh) {
// 慢启动阶段:指数增长
tp->snd_cwnd++;
} else {
// 拥塞避免阶段:CUBIC曲线增长
u32 delta = tcp_time_stamp - ca->epoch_start;
u32 t = delta >> bic_scale;
// CUBIC函数:W(t) = C*(t-K)^3 + Wmax
u32 target = ca->bic_origin +
((t * t * t) / CUBIC_SHIFT);
if (target > tp->snd_cwnd)
tp->snd_cwnd = min(target, tp->snd_cwnd + 1);
}
}
3.5 不同实现的性能对比
| 实现 | 吞吐量 | 延迟 | 内存占用 | 代码量 | 适用场景 |
|---|---|---|---|---|---|
| Linux内核 | 10Gbps+ | 微秒级 | 大 | 10万行+ | 服务器 |
| DPDK | 100Gbps+ | 纳秒级 | 中等 | 定制 | 高性能 |
| lwIP | 100Mbps | 毫秒级 | 几十KB | 2万行 | 嵌入式 |
| uIP | 1Mbps | 毫秒级 | 几KB | 几千行 | 单片机 |
3.6 实现的挑战与发展趋势
当前挑战
- 性能瓶颈:多核扩展性、锁竞争
- 新硬件适配:RDMA、智能网卡
- 安全威胁:DDoS攻击、协议漏洞
未来趋势
🚀 演进方向:
- **XDP/eBPF**:内核可编程数据平面
- **QUIC协议**:基于UDP的下一代传输协议
- **TLS/加密**:协议栈原生加密支持
- **用户态协议栈**:DPDK、F-Stack普及
总结
TCP/IP从ARPANET时代的实验性协议,发展成为互联网的基石,经历了近50年的演进:
- 由来:体现了"简单核心、智能边缘"的设计智慧
- 应用:渗透到数字世界的每个角落,从网页浏览到5G通信
- 实现:在不同场景下有不同优化,从Linux内核到嵌入式lwIP
无论技术如何发展,TCP/IP所代表的分层抽象和端到端原则,仍然是网络设计的核心思想。