TCP/IP技术概述

0 阅读8分钟

tcp/ip技术概述

1 tcp/ip技术由来

1.1 从ARPANET到Internet

image.png 诞生背景

  • 1969年,ARPANET最初使用NCP(Network Control Protocol)
  • 随着网络规模扩大,NCP的局限性凸显
  • 需要一种能够连接异构网络的通用协议

1.2 为什么叫TCP/IP?

TCP/IP实际上是一个协议族,以两个核心协议命名:

  • TCP(传输控制协议):负责可靠传输
  • IP(网际协议):负责路由寻址

1.3 TCP/IP设计哲学

TCP/IP的设计体现了几个关键思想: 🎯 核心设计原则:

  1. 端到端原则:智能在端点,网络核心保持简单
  2. 鲁棒性:网络故障时能自动恢复
  3. 无状态设计:网络层不保存连接状态
  4. 分层抽象:各层独立演进

经典名言

"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

image.png

2.2 日常生活中的应用场景

🌐 Web浏览
  • HTTP/HTTPS协议基于TCP
  • 每次打开网页都在使用TCP/IP
  • 示例:浏览器输入URL到页面显示的全过程

image.png

📧 电子邮件
  • 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

典型问题排查流程

image.png

3 tcp/ip的实现

3.1 协议栈的软件架构

TCP/IP协议栈的实现方式主要有三种:

实现方式代表特点适用场景
内核态协议栈Linux内核性能高,与操作系统紧密结合服务器、PC
用户态协议栈DPDK, Netmap零拷贝,可定制,性能极致高性能网络、NFV
轻量级协议栈lwIP, uIP资源占用小,可移植性强嵌入式设备、RTOS

Linux 内核实现

image.png

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内核接收路径

image.png 关键函数调用链: 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万行+服务器
DPDK100Gbps+纳秒级中等定制高性能
lwIP100Mbps毫秒级几十KB2万行嵌入式
uIP1Mbps毫秒级几KB几千行单片机

3.6 实现的挑战与发展趋势

当前挑战
  1. 性能瓶颈:多核扩展性、锁竞争
  2. 新硬件适配:RDMA、智能网卡
  3. 安全威胁:DDoS攻击、协议漏洞
未来趋势
🚀 演进方向:
- **XDP/eBPF**:内核可编程数据平面
- **QUIC协议**:基于UDP的下一代传输协议
- **TLS/加密**:协议栈原生加密支持
- **用户态协议栈**:DPDK、F-Stack普及

总结

TCP/IP从ARPANET时代的实验性协议,发展成为互联网的基石,经历了近50年的演进:

  • 由来:体现了"简单核心、智能边缘"的设计智慧
  • 应用:渗透到数字世界的每个角落,从网页浏览到5G通信
  • 实现:在不同场景下有不同优化,从Linux内核到嵌入式lwIP

无论技术如何发展,TCP/IP所代表的分层抽象端到端原则,仍然是网络设计的核心思想。