# TCP三次握手与四次挥手
# 1. TCP三次握手
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers);
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
完成三次握手,客户端与服务器开始传送数据。
# 2. TCP四次挥手
客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送;
服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号;
服务器B关闭与客户端A的连接,发送一个FIN给客户端A;
客户端A发回ACK报文确认,并将确认序号设置为收到序号加1。

# 3.三次握手的必要性
三次握手的主要目的是确认双方的接收和发送能力,确保连接的可靠性:
- 确认双方收发能力:客户端发送SYN确认自己能发送,服务器回复SYN+ACK确认自己能收发,客户端再发送ACK确认自己能接收。
- 防止已失效的连接请求:网络延迟可能导致客户端的连接请求在很久以后到达服务器,三次握手可以防止建立已失效的连接。
- 同步初始序列号:双方通过交换初始序列号来同步数据传输。
# 4. 四次挥手的原因
TCP连接是全双工的,需要分别关闭两个方向的数据传输:
- 独立关闭:当一方发送FIN报文时,只是关闭了该方向的数据传输,另一方向仍可以继续发送数据。
- 数据处理时间:服务器收到FIN后可能还有数据未发送完毕,需要时间处理完剩余数据。
- 确保数据完整性:分开关闭确保双方都能完整接收和发送所有数据。
# 5. TCP可靠性保证机制
TCP通过多种机制保证数据传输的可靠性:
- 数据包校验:通过校验和检测数据在传输过程中是否出错。
- 序列号和确认应答:通过序列号对数据包进行编号,接收方通过确认应答告知发送方数据已接收。
- 超时重传:发送方在一定时间内未收到确认应答时会重传数据。
- 连接管理:通过三次握手建立连接,四次挥手断开连接,确保连接的可靠性。
- 流量控制:通过滑动窗口机制控制发送方的发送速度,防止接收方缓冲区溢出。
- 拥塞控制:通过慢启动、拥塞避免等算法控制网络拥塞。
- 数据重排序:接收方将乱序到达的数据包重新排序后交给应用层。
# 6. TCP报文

- 序号:Seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。
- 确认序号:Ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,Ack=Seq+1。
# 6.1 tcp的6种标志位的分别代表
| 标志位 | 全称 | 含义 |
|---|---|---|
| SYN | synchronous | 发起一个新连接 |
| ACK | acknowledgement | 确认序号有效 |
| PSH | push | 接收方应该尽快将这个报文交给应用层 |
| FIN | finish | 释放一个连接 |
| RST | reset | 重置连接 |
| URG | urgent | 紧急指针(urgent pointer)有效 |
不要将确认序号Ack与标志位中的ACK搞混了
# 6.2 握手过程具体报文内容
- 第一次握手:客户端发送一个TCP的SYN标志位置1的包指明客户打算连接的服务器的端口,以及初始序号X,保存在包头的序列号(Sequence Number)字段里

- 第二次握手:服务器发回确认包(ACK)应答。即SYN标志位和ACK标志位均为1同时,将确认序号(Acknowledgement Number)设置为客户的ISN加1以,即X+1

- 第三次握手:客户端再次发送确认包(ACK)SYN标志位为0,ACK标志位为1,并且把服务器发来ACK的序号字段+1,放在确定字段中发送给对方,并且在数据段放写ISN的+1

为了方便查看,图片中标志位的所占字节大小与实际不符
初始序列号(ISN):当两台主机需要使用TCP传输协议传输数据时,会创建一个新的连接。这涉及希望启动连接的第一个主机,以生成所谓的初始序列号(ISN),它基本上是我们正在查看的序列字段中包含的第一个序列号。
# 7. TCP状态迁移
# 7.1 客户端TCP状态迁移
CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED
# 7.2 服务器TCP状态迁移
CLOSED->LISTEN->SYN收到->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED
# 8. 各个状态的意义如下
| 标志位 | 含义 |
|---|---|
| LISTEN | 侦听来自远方TCP端口的连接请求 |
| SYN-SENT | 在发送连接请求后等待匹配的连接请求; |
| SYN-RECEIVED | 在收到和发送一个连接请求后等待对连接请求的确认; |
| ESTABLISHED | 代表一个打开的连接,数据可以传送给用户; |
| FIN-WAIT-1 | 等待远程TCP的连接中断请求,或先前的连接中断请求的确认; |
| FIN-WAIT-2 | 从远程TCP等待连接中断请求; |
| CLOSE-WAIT | 等待从本地用户发来的连接中断请求; |
| CLOSING | 等待远程TCP对连接中断的确认; |
| LAST-ACK | 等待原来发向远程TCP的连接中断请求的确认; |
| TIME-WAIT | 等待足够的时间以确保远程TCP接收到连接中断请求的确认; |
| CLOSED | 没有任何连接状态; |
# 9. 其他
# 9.1 为什么TCP链接不是两次
为了双方都能明确自己和对方的收、发能力是正常的。
第一次握手:客户端无法知道自己发送是否正常,但是服务端收到请求,知道客户端发送能力正常,自己服务端的接受能力正常;
第二次握手:服务的发送请求到客户端,客户端知道服务端接受到自己第一次握手的请求了,客户端知道自己的发送和接受能力正常,服务端的发送和接受能力正常;
第三次握手:服务端接收到客户端的确认消息,确认了服务端的发送,接受能力正常。
| 视角 | 客收 | 客发 | 服收 | 服发 |
|---|---|---|---|---|
| 客视角 | 二 | 一 + 二 | 一 + 二 | 二 |
| 服视角 | 二 + 三 | 一 | 一 | 二 + 三 |
# 9.2 为什么TCP断开链接需要四次
第一次挥手:A 说“我没啥要说的了” 第二次挥手:B 回答“我知道了”,但是 B 可能还会有要说的话,A 不能要求 B 跟着自己的节奏结束通话 第三次挥手:于是 B 可能又巴拉巴拉说了一通,最后 B 说“我说完了” 第四次挥手:A 回答“知道了”,这样通话才算结束。
因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手
# 9.3 确认号与序列号关系
确认号:其数值等于发送方的发送序号 +1(即接收方期望接收的下一个序列号)
# 9.4 TCP协议如何来保证传输的可靠性
TCP提供一种面向连接的、可靠的字节流服务。其中,面向连接意味着两个使用TCP的应用(通常是一个客户和一个服务器)在彼此交换数据之前必须先建立一个TCP连接。在一个TCP连接中,仅有两方进行彼此通信;而字节流服务意味着两个应用程序通过TCP链接交换8bit字节构成的字节流,TCP不在字节流中插入记录标识符。
# 9.5 对于可靠性,TCP通过以下方式进行保证
数据包校验:目的是检测数据在传输过程中的任何变化,若校验出包有错,则丢弃报文段并且不给出响应,这时TCP发送数据端超时后会重发数据;
对失序数据包重排序:既然TCP报文段作为IP数据报来传输,而IP数据报的到达可能会失序,因此TCP报文段的到达也可能会失序。TCP将对失序数据进行重新排序,然后才交给应用层;
丢弃重复数据:对于重复数据,能够丢弃重复数据;
应答机制:当TCP收到发自TCP连接另一端的数据,它将发送一个确认。这个确认不是立即发送,通常将推迟几分之一秒;
超时重发:当TCP发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段;
流量控制:TCP连接的每一方都有固定大小的缓冲空间。TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据,这可以防止较快主机致使较慢主机的缓冲区溢出,这就是流量控制。TCP使用的流量控制协议是可变大小的滑动窗口协议。
