> For the complete documentation index, see [llms.txt](https://yangsx95.gitbook.io/notes/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://yangsx95.gitbook.io/notes/computer-science/ji-suan-ji-wang-luo/wang-luo-ceng/tcp.md).

# TCP

TCP相较于UDP，具有可靠性，但是相对的占用系统资源；而UDP没有TCP那些可靠的机制，所以相比较于TCP更快。

### 单工、半双工、全双工

根据通信双方的分工和信号传输方向可将通信分为三种方式：单工、半双工与全双工

**单工**：数据只能在单个方向上传输。比如广播 **半双工**：数据可以在两个方向上传输，在同一时刻只允许一个方向传输。 比如对讲机 **全双工**：数据可以在两个方向上传输，在同一时刻也允许两个方向传输。比如手机通话

> TCP 和 UDP 都是全双工

### TCP 协议

TCP(Transmission Control Protocol)传输控制协议，是主机对主机层的传输控制协议，用于提供可靠的连接服务。为了保证TCP协议的可靠性，保证数据正确的传输给对方，在连接时需要进行**三次握手**，确保双方可以正常通信，在断开连接时需要进行**四次挥手**，确保双方数据都传输完毕，保证数据传输完毕。

#### 三次握手协议

三次握手（Three-Way-Handshake）即建立TCP连接，就是指建立一个TCP连接时，客户端和服务端总共需要发送三个包确认连接的建立

借用一下这个小例子，来描述三次握手的流程：

> 土豆土豆 我是地瓜，收到请回答 地瓜收到，土豆收到请回答 土豆收到

步骤1和2：确认地瓜可以正常收到土豆的消息 步骤2和3：确认土豆可以正常收到地瓜的消息

这三步就可以保证土豆和地瓜正常通信，这就是三次握手。下面是具体流程：

![](/files/hpxkotq10QC2hM42mZYz)

1. 客户端发送第一次握手请求，并携带SYN=j（j是一个唯一的随机数，代表此次请求），此时客户端此时变为已发送的状态(SYN\_SEND)
2. 服务端接收到客户端的握手请求，此时进入 LISTEN 打开状态
3. 服务端发送ACK确认包，此时是第二次握手，ACK=j+1表示是哪个请求，并再次发送SYN=k(k也是唯一随机数，用来代表此次请求)
4. 客户但接收到ACK信息，此时客户端进入 ESTABLISHED 状态，代表客户端到服务端信息发送正常
5. 客户端发送ACK确认信息给服务端，此时是第三次握手，告诉服务端可以正常收到他的信息
6. 服务端收到ACK信息后，将状态变为ESTABLISHED，双方可以正常通信， 整个握手流程结束

#### 四次挥手协议

四次挥手（Four-Way-Wavehand）即终止TCP连接，就是断开一个TCP连接时，客户端和服务短短总共需要发送四个包确认连接的断开

目的：保证客户端和服务端都没有消息传递了再关闭

> 男朋友（客户端）：我有点事先不聊了 女朋友（服务端）：好的，等下，我还有点事没讲完 ... 女朋友（服务端）：好了，我没事了挂了吧 男朋友（客户端）：喂.... （随即男朋友也挂断了电话）

通过四次通信，确认tcp通信已经完成，并关闭连接，这就是四次挥手，下面是具体流程：

![](/files/1t3qVje3qpgwrM00CIgk)

1. 客户端发送FIN M（M是发送id），表示客户端要结束了，此时客户端进入FIN\_WAIT\_1 状态
2. 服务端接收到请求后，进入CLOSE\_WAIT状态(等待关闭)，再向客户端发送ACK确认包，告诉客户端，我已经接收到了关闭请求
3. 等到服务端数据传送完毕，发送FIN N给客户端，告诉客户端处理完毕，即将进入关闭状态
4. 客户端接收到 FIN N，返回ACK确认包，此时服务端进入关闭状态

#### TCP 长连接、短连接

**长连接**，指在一个TCP连接上可以连续发送多个数据包，在TCP连接保持期间，如果没有数据包发送，需要双方发检测包以维持此连接（心跳机制），一般需要自己做在线维持。 过程： `连接→数据传输→保持连接(心跳)→数据传输→保持连接(心跳)→……→关闭连接`

**短连接**是指通信双方有数据交互时，就建立一个TCP连接，数据发送完成后，则断开此TCP连接，比如http连接

#### TCP通信原理

对于TCP通信来说，每个TCP Socket的内核中都有一个发送缓冲区和一个接收缓冲区，**TCP全双工的工作模式及TCP的滑动窗口就是依赖于这两个独立的Buffer和该Buffer的填充状态**。

![tcp通信原理](/files/FIOMEl7AIgdD9jaLEtmy)

进程调用Socket的send发送数据的时候，一般情况下是将数据从应用层用户的Buffer里复制到Socket的内核发送缓冲区，然后send就会在上层返回。换句话说，send返回时，数据不一定会被发送到对端。

接收端接收到数据后，将数据放在接收缓冲区中，若应用进程一直没有调用Socket的read方法进行读取，那么该数据会一直被缓存在接收缓冲区内。不管进程是否读取Socket，对端发来的数据都会经过内核接收并缓存到Socket的内核接收缓冲区。 read索要做的工作，就是把内核接收缓冲区中的数据复制到应用层用户的Buffer里。

#### 滑动窗口协议

滑动窗口协议用于控制流量，TCP滑动窗口分为接受窗口和发送窗口。滑动窗口协议是**传输层进行流控**的一种措施，**接收方通过通告发送方自己的窗口大小，从而控制发送方的发送速度**，从而达到防止发送方发送速度过快而导致自己被淹没的目的。

视频演示：[优酷-TCP sliding window](https://v.youku.com/v_show/id_XNDg1NDUyMDUy.html)

视频中发送端向接收端发送 segment 数据片段，接收端接收到数据片段后给发送端发送ACK确认包。当发送端接收到3个ack信号时，即发送端滑动窗口满了的时候，才会再次发送，如果未满，说明接收端仍然在处理。而接收端只有在收到3个segemnt信号时，滑动窗口才会移动，才能再次接收segement。从而达到限流的目的。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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://yangsx95.gitbook.io/notes/computer-science/ji-suan-ji-wang-luo/wang-luo-ceng/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.
