# 3. TCP

## 1. TCP 协议的特点

1. TCP 是**面向连接**（虚连接）的传输层协议
2. 每一条 TCP 连接只能有两个端点，每一条 TCP 连接只能是**点对点的**
3. TCP 提供可靠交付的服务，无差错，不丢失，不重复，按序到达（**可靠有序，不丢不重**）
4. TCP 提供**全双工通信**
   * **发送**缓存：准备发送的数据 & 已发送但尚未收到确认的数据
   * **接收**缓存：按序到达但尚未被接收应用程序读取的数据 & 不按序到达的数据
5. TCP **面向字节流**：TCP 把应用交下来的数据看成仅仅是一连串的无结构的字节流

![](/files/-MENBZDRV8Xd3uZM-gYh)

## 2. TCP 报文段首部格式

![](/files/-MENBlN6JGjib_cWzs10)

* **序号（seq）：**&#x5728;一个 TCP 连接中传送的字节流中的每一个字节都按序编号，本字段表示本报文段所发送数据的第一个字节的序号
* **确认号（ack）：**&#x671F;望收到对方下一个报文段的第一个数据字节的序号。如果确认号为 N，则证明到序号 N - 1 为止的所有数据都已正确收到
* **数据偏移（首部长度）：**&#x54;CP 报文段的数据起始处距离 TCP 报文段的起始处有多远，以 4B 为单位，即 1 个数值是 4B
* **紧急位 URG：**&#x55;RG = 1 时，表示此报文段中有紧急数据，是高优先级的数据，应尽快传送，不用再缓存里排队，配合紧急指针字段使用
* **确认位 ACK：**&#x41;CK = 1 时确认号有效，在连接建立之后所有传送的报文段都必须把 ACK 置为 1
* **推送位 PSH：**&#x50;SH = 1 时，接收方尽快交付接受应用程序，不再等到缓存填满再向上交付（和紧急位是对应的，紧急位是发送发优先发送，推送位是接收方优先向上交付）
* **复位 RST：**&#x52;ST = 1 时，表明 TCP 连接中出现严重差错，必须释放连接，然后再**重新建立传输连接**
* **同步位 SYN：**&#x53;YN = 1 时，表明是一个**连接请求**/**连接接收报文**
* **终止位 FIN：**&#x46;IN = 1 时，表明此报文段发送方数据已发送完，要求释放连接
* **窗口：**&#x6307;发送本报文段的一方的接收窗口，即现在允许对方发送的数据量
* **检验和：**&#x68C0;验首部 + 数据，检验时要加上 12B 伪首部，伪首部第四个字段是 6
* **紧急指针：**&#x55;RG = 1 时才有意义，指出本报文段中紧急数据的字节数
* **选项：**&#x6700;大报文段长度 MSS、窗口扩大、时间戳、选择确认......

## 3. TCP 连接管理

TCP 连接传输的三个阶段：**连接建立 -> 数据传送 -> 连接释放**

TCP 连接的建立采用**客户服务器方式**，主动发起连接建立的应用进程叫做**客户**，而被动等待连接建立的应用进程叫**服务器**

### 3.1 TCP 连接建立

![](/files/-MENGJbqVHTukf-e9nn5)

刚开始客户端处于 **closed 状态**，服务端处于 **listen 状态**

**第一次握手：**&#x5BA2;户端发送连接请求报文段（**SYN = 1，seq = x（随机）**），无应用层数据。此时客户端处于 **SYN\_Send （同步发送）状态**

**第二次握手：**&#x670D;务端收到客户端的连接请求报文后，为该 TCP 连接分配缓存和变量，并向客户端返回确认报文（**SYN = 1，ACK = 1，seq = y（随机），ack = x + 1**），允许连接，无应用层数据。此时服务端处于 **SYN\_REVD（同步接收）状态**

**第三次握手：**&#x5BA2;户端收到连接请求报文后，会发送一个对确认的确认报文（**ACK = 1，seq = x + 1，ack = y + 1**），**可以携带数据**。此时客户端**处于 established 状态**

服务器收到确认报文后，也会**处于 established 状态**。此时，双方建立了连接

#### 1. 三次握手的作用

1. 确认双方的接受能力，发送能力是否正常
2. 指定自己的初始化序列号，为后面的可靠传输做准备

#### 2. SYN 洪泛攻击

SYN 洪泛攻击发生在 OSI 第四层，这种方式利用 TCP 协议的特性，就是三次握手。攻击者发送 TCP SYN，SYN 是 TCP 三次握手中的第一个数据包，而当服务器返回 ACK 后，该攻击者就不对其进行再确认，那这个 TCP 连接就处于挂起状态，也就是所谓的半连接状态，服务器收不到再确认的话，还会重复发送 ACK 给攻击者。这样更加浪费服务器的资源。攻击者就对服务器发送非常大量的这种 TCP 连接，由于每一个都无法完成三次握手，所以在服务器上，这些 TCP 连接会因为挂起这种状态而消耗 CPU 和内存，最后服务器可能死机，就无法为正常用户提供服务了。

**解决方法：**&#x53;YN cookie

### 3.2 TCP 连接释放

参与一条 TCP 连接的两个进程中的**任何一个都能终止该连接**，连接结束后，主机中的资源（缓存和变量）将被释放

![](/files/-MENZokxK82XLLOqlCnW)

刚开始双方都处于 established 状态，假如是客户端先发起关闭请求，则：

第一次挥手：客户端发送**连接释放报文段**（**FIN = 1，seq = u（前面已传送数据的最后一个字节序号 + 1）**），停止发送数据，主动关闭 TCP 连接。此时客户端处于 **FIN-WAIT-1 状态**

第二次挥手：服务端收到 FIN 报文后，返回一个确认报文段（**ACK = 1，seq = v，ack = u + 1**）。此时服务端处于 **CLOSE-WAIT 状态**

第三次挥手：服务端发完数据，就发出连接释放报文段（**FIN = 1，ACK = 1，seq = w，ack = u + 1**），主动关闭 TCP 连接。此时服务端处于 **LAST-ACK 状态**

第四次挥手：客户端返回一个确认报文段（**ACK = 1，seq = u + 1，ack = w + 1**），再等到时间等待计时器设置的 2MSL（最长报文段寿命）后，连接彻底关闭

## 4. TCP 可靠传输

**传输层：**&#x4F7F;用 TCP 实现可靠传输

**网络层：**&#x63D0;供尽最大努力交付，不可靠传输

**可靠：**&#x4FDD;证接收方进程从缓存区读出字节流与发送方发出的字节流是完全一样的

**TCP 实现可靠传输的机制：**

1. 校验：与 UDP 校验一样，**增加伪首部**
2. 序号
3. 确认
4. 重传

### 4.1 序号

一个字节占一个序号

**序号字段**指的是一个报文段第一个字节的序号

![](/files/-MERJ-VxsrwQj-0Cj7qe)

### 4.2 确认

TCP 默认使用累计确认

![](/files/-MERJLsV9R0yrXxqOzcH)

### 4.3 重传

确认重传不分家，TCP 的发送方在**规定的时间（重传时间）**&#x5185;没有收到确认就要重传已发送的报文段。超时重传

TCP 采用自适应算法，动态改变重传时间 **RTTs**（加权平均往返时间）

* 当仅发送第一个报文段时，第一个报文段的往返时间
* 当发送了两个报文段时，前两个报文段的平均往返时间
* 以此类推......动态改变

**重传时间的缺点：**&#x53EA;有当过了重传时间后，才能重发，在重传时间内，就需要一直等待，这样等待的时间过长

#### 快速重传

冗余 ACK （冗余确认）：每当比期望序号大的失序报文段到达时，发送一个**冗余 ACK**，指明下一个期待字节的序号

发送方已发送 1，2，3，4，5 报文段

* 接收方收到 1，返回给 1 的确认（确认号为 2 的第一个字节）
* 接收方收到 3，返回给 1 的确认（确认号为 2 的第一个字节）
* 接收方收到 4，返回给 1 的确认（确认号为 2 的第一个字节）
* 接收方收到 5，返回给 1 的确认（确认号为 2 的第一个字节）

发送方收到 **3 个对于报文段 1 的冗余 ACK** -> 认为 2 报文段丢失，重传 2 号报文段

## 5. TCP 流量控制

**流量控制：**&#x8BA9;**发送方慢点**，要让接收方来得及接收

TCP 利用**滑动窗口**机制来实现流量控制

在通信过程中，接收方根据自己**接收缓存的大小**，动态地调整发送方的发送窗口大小，即接收窗口rwnd（接收方设置确认报文段的**窗口字段**来将rwnd通知给发送方），**发送方的发送窗口 = Min（接收窗口 rwnd，拥塞窗口 cwnd）**

**例：**&#x41; 向 B 发送数据，连接建立时，B 告诉 A：“我的 rwnd = 400B”，设每一个报文段 100B，报文段序号初始值为 1

![](/files/-MERNHVoKkAcPO0_IG5c)

TCP 为每一个连接设有一个持续计时器，只要 TCP 连接的一方收到对方的零窗口通知，就启动持续计时器

若持续计时器设置的时间到期，就发送一个零窗口**探测报文段**。接收方收到探测报文段时给出现在的窗口值

若窗口仍然是 0，那么发送方就重新设置持续计时器

## 6. TCP 拥塞控制

**出现拥塞的条件：**&#x5BF9;资源需求的总和 > 可用资源

网络中有许多资源同时呈现供应不足 -> 网络性能变坏 -> 网络吞吐量将随输入负荷增大而下降

**拥塞控制：**&#x9632;止过多的数据注入到网络中（全局性）

### 6.1 慢开始 & 拥塞避免

![](/files/-MERP4VFrfa1LqsbyIFB)

**一个传输轮次：**&#x53D1;送一批报文段并收到它们的确认的时间

**一个往返时延 RTT：**&#x5F00;始发送一批拥塞窗口内的报文段到开始发送下一批拥塞窗口内的报文段的时间

### 6.2 快重传 & 快恢复

![](/files/-MERQBvFDmB_f0B_XZWm)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://lfool.gitbook.io/computer-network/di-wu-zhang-chuan-shu-ceng/3.-tcp.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
