C语言核心概念复习——TCP/IP协议栈

TCP/IP协议栈详细解析

一、TCP头部结构详解

TCP头部格式(20字节基本头部 + 最多40字节选项)

text

复制代码
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          16位源端口          |         16位目的端口          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       32位序列号                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       32位确认号                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 数据 |  保留 | U | A | P | R | S | F |    16位窗口大小      |
| 偏移 |       | R | C | S | S | Y | I |(接收缓冲区剩余大小)|
| 4位  |  6位  | G | K | H | T | N | N |                    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|        16位校验和          |        16位紧急指针           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    可选选项(最多40字节)                  |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                            数据                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

各字段详细说明

1. 端口相关字段
  • 16位源端口(Source Port):发送方应用程序的端口号

  • 16位目的端口(Destination Port):接收方应用程序的端口号

  • 端口范围:0-65535(0-1023为系统保留端口)

2. 序列控制字段
  • 32位序列号(Sequence Number):当前数据包的序号

    • 用于标识数据包的顺序

    • 防止数据包乱序

    • 初始序列号在建立连接时协商

  • 32位确认号(Acknowledgment Number):期望收到的下一个数据包的序号

    • 表示已经成功收到的数据

    • 采用累积确认机制

3. 头部长度和标志位
  • 4位头部长度(Data Offset):TCP头部长度(以4字节为单位)

    • 最小值为5(表示20字节)

    • 最大值为15(表示60字节)

  • 6位保留位(Reserved):保留未使用,必须设为0

4. 6个控制标志位(各占1位)
复制代码
URG ACK PSH RST SYN FIN
 1   1   0   0   1   0   ← 例如:SYN+ACK包
  • URG(Urgent):紧急数据标志

    • 当URG=1时,表示有紧急数据

    • 紧急指针字段有效

  • ACK(Acknowledgment):确认标志

    • 当ACK=1时,确认号字段有效

    • 建立连接后所有数据包ACK都应为1

  • PSH(Push):推送标志

    • 当PSH=1时,要求接收方立即将数据交给应用程序

    • 避免缓冲区延迟

  • RST(Reset):重置连接标志

    • 当RST=1时,表示连接出现严重错误,需要重建连接
  • SYN(Synchronize):同步序列号标志

    • 当SYN=1时,表示请求建立连接

    • 在三次握手的前两个包中使用

  • FIN(Finish):结束连接标志

    • 当FIN=1时,表示发送方数据已发送完毕,请求关闭连接

    • 在四次挥手时使用

5. 流量控制字段
  • 16位窗口大小(Window Size):接收方缓冲区剩余空间

    • 用于流量控制,防止发送方发送过快

    • 实现滑动窗口协议的基础

    • 接收端通过此字段告知发送端还能接收多少数据

6. 校验和紧急指针
  • 16位校验和(Checksum):用于检测头部和数据的错误

    • 覆盖TCP头部、数据和伪头部

    • 接收方通过校验和验证数据完整性

  • 16位紧急指针(Urgent Pointer):紧急数据的偏移量

    • 当URG=1时有效

    • 指向紧急数据的最后一个字节的位置

7. 可选选项
  • 可选选项(Options):最多40字节的额外信息

    • 最大报文段大小(MSS)

    • 窗口扩大因子

    • 时间戳

    • 选择性确认(SACK)

    • 无操作(NOP)等

紧急数据(带外数据)处理

复制代码
// 发送紧急数据(带外数据)
send(conn_fd, buf, sizeof(buf), MSG_OOB);  // MSG_OOB标志表示紧急数据

// 接收紧急数据
recv(conn_fd, buf, sizeof(buf), MSG_OOB);

// 设置socket选项(一次一个紧急数据)
int opt = 1;
setsockopt(sock_fd, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt));

TCP缓冲区大小

  • 发送缓冲区:默认约2KB

  • 接收缓冲区:默认约256KB

  • 可以通过setsockopt()函数调整

二、IP头部结构详解

IP头部格式(20字节基本头部 + 最多40字节选项)

复制代码
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 版本 | 头长 |   服务类型   |           总长度               |
| 4位  | 4位  |   TOS 8位   |          16位                |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          标识(16位)         | 标志 |      段偏移           |
|                             | 3位  |        13位          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  生存时间   |   协议      |           头部校验和          |
|  TTL 8位   |   8位      |             16位              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    源IP地址(32位)                      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                  目的IP地址(32位)                      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    可选选项(最多40字节)                  |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

各字段详细说明

1. 版本和头部长度
  • 4位版本号(Version):IP协议版本

    • IPv4:值为4

    • IPv6:值为6

  • 4位头部长度(IHL):IP头部长度(以4字节为单位)

    • 最小值为5(表示20字节)

    • 最大值为15(表示60字节)

2. 服务类型和总长度
  • 8位服务类型(TOS,Type of Service):服务质量参数

    • 用于区分不同服务的优先级

    • 包含:优先级、延迟、吞吐量、可靠性、成本

  • 16位总长度(Total Length):IP数据包总长度

    • 包括IP头部和数据部分

    • 最大值为65535字节

    • 受MTU限制

3. 分片相关字段
  • 16位标识(Identification):数据包标识

    • 用于标识属于同一原始数据包的所有分片

    • 发送方为每个数据包分配唯一标识

  • 3位标志(Flags):分片控制标志

    • 第1位:保留,必须为0

    • 第2位:不分片(DF,Don't Fragment)

      • DF=1:不允许分片

      • DF=0:允许分片

    • 第3位:更多分片(MF,More Fragments)

      • MF=1:后面还有分片

      • MF=0:这是最后一个分片或没有分片

  • 13位段偏移(Fragment Offset):分片偏移量

    • 表示当前分片在原数据包中的位置

    • 以8字节为单位

4. 生存时间和协议
  • 8位生存时间(TTL,Time To Live):数据包生存时间

    • 每经过一个路由器减1

    • 当TTL=0时,数据包被丢弃

    • 防止数据包在网络中无限循环

  • 8位协议(Protocol):上层协议类型

    • ICMP:1

    • TCP:6

    • UDP:17

    • 其他协议有相应的编号

  • 16位头部校验和(Header Checksum):IP头部校验和

    • 只校验IP头部

    • 每个路由器都需要重新计算

5. IP地址
  • 32位源IP地址(Source Address):发送方IP地址

  • 32位目的IP地址(Destination Address):接收方IP地址

6. MTU概念
  • MTU(Maximum Transmission Unit):最大传输单元

    • 指数据链路层能传输的最大数据包大小

    • 以太网MTU通常为1500字节

    • 当IP数据包超过MTU时需要分片

三、以太网数据帧格式

以太网帧结构

复制代码
+----------------+----------------+----------------+----------------+----------------+
|   目的MAC地址   |    源MAC地址   |     类型       |      数据      |     CRC校验    |
|   6字节(48位)  |  6字节(48位)  |  2字节(16位) |  46-1500字节  |  4字节(32位)  |
+----------------+----------------+----------------+----------------+----------------+

各字段详细说明

1. MAC地址字段
  • 6字节目的物理地址(Destination MAC Address):接收方的MAC地址

    • 如果目的MAC为FF:FF:FF:FF:FF:FF,表示广播地址

    • 如果目的MAC为01:00:5E:xx:xx:xx,表示组播地址

  • 6字节源物理地址(Source MAC Address):发送方的MAC地址

2. 类型字段
  • 2字节类型(Type/EtherType):上层协议类型

    • 0x0800:IPv4协议

    • 0x0806:ARP协议(地址解析协议)

    • 0x86DD:IPv6协议

    • 0x8035:RARP协议(反向地址解析协议)

3. 数据字段
  • 46-1500字节数据(Data/Payload):有效载荷

    • 最小46字节:如果数据不足46字节需要填充

    • 最大1500字节:受MTU限制

    • 包含IP头部、传输层头部和应用层数据

4. 校验字段
  • 4字节CRC校验(Frame Check Sequence):循环冗余校验

    • 用于检测数据帧在传输过程中是否出错

    • 接收方通过CRC校验验证数据完整性

特殊协议说明

  • ping命令:使用ICMP协议(Internet控制报文协议)

  • ARP协议:用于IP地址到MAC地址的解析

四、TCP服务器/客户端编程模型

TCP服务器编程流程

复制代码
// 1. 创建socket
int sock_fd = socket(AF_INET, SOCK_STREAM, 0);

// 2. 绑定地址
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8888);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));

// 3. 监听连接
listen(sock_fd, 5);  // 5为等待队列长度

// 4. 接受连接
struct sockaddr_in client_addr;
socklen_t addr_len = sizeof(client_addr);
int conn_fd = accept(sock_fd, (struct sockaddr*)&client_addr, &addr_len);

// 5. 发送数据
send(conn_fd, buffer, strlen(buffer), 0);

// 6. 接收数据
recv(conn_fd, buffer, sizeof(buffer), 0);

// 7. 关闭连接
close(conn_fd);
close(sock_fd);

TCP客户端编程流程

复制代码
// 1. 创建socket
int sock_fd = socket(AF_INET, SOCK_STREAM, 0);

// 2. 可以bind(但不建议,系统会自动分配)
// struct sockaddr_in client_addr;
// bind(sock_fd, (struct sockaddr*)&client_addr, sizeof(client_addr));

// 3. 连接服务器
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8888);
inet_pton(AF_INET, "192.168.1.100", &server_addr.sin_addr);
connect(sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));

// 4. 接收数据
recv(sock_fd, buffer, sizeof(buffer), 0);

// 5. 发送数据
send(sock_fd, buffer, strlen(buffer), 0);

// 6. 关闭连接
close(sock_fd);

关键点说明

  1. 服务器必须bind:指定监听端口

  2. 客户端不建议bind:系统会自动分配端口

  3. listen的第二个参数:等待连接队列的最大长度

  4. accept会阻塞:直到有客户端连接

  5. connect会阻塞:直到连接成功或失败

  6. send/recv可能阻塞:取决于socket是否设置为非阻塞模式

相关推荐
0xDevNull15 小时前
Linux切换JDK版本详细教程
linux
进击的丸子15 小时前
虹软人脸服务器版SDK(Linux/ARM Pro)多线程调用及性能优化
linux·数据库·后端
茶杯梦轩16 小时前
从零起步学习RabbitMQ || 第二章:RabbitMQ 深入理解概念 Producer、Consumer、Exchange、Queue 与企业实战案例
服务器·后端·消息队列
Johny_Zhao2 天前
OpenClaw安装部署教程
linux·人工智能·ai·云计算·系统运维·openclaw
RuoZoe2 天前
重塑WPF辉煌?基于DirectX 12的现代.NET UI框架Jalium
c语言
blasit2 天前
笔记:Qt C++建立子线程做一个socket TCP常连接通信
c++·qt·tcp/ip
YuMiao3 天前
gstatic连接问题导致Google Gemini / Studio页面乱码或图标缺失问题
服务器·网络协议
chlk1234 天前
Linux文件权限完全图解:读懂 ls -l 和 chmod 755 背后的秘密
linux·操作系统
舒一笑4 天前
Ubuntu系统安装CodeX出现问题
linux·后端
改一下配置文件4 天前
Ubuntu24.04安装NVIDIA驱动完整指南(含Secure Boot解决方案)
linux