文章目录
- TCP
-
- [TCP 的核心特点](#TCP 的核心特点)
- [TCP 与 UDP 特性对比](#TCP 与 UDP 特性对比)
- [TCP 标志位](#TCP 标志位)
- [TCP 的三次握手(建立连接)](#TCP 的三次握手(建立连接))
-
- [TCP 三次握手概述](#TCP 三次握手概述)
- [图解 TCP 三次握手](#图解 TCP 三次握手)
- 为什么需要三次握手,而不是两次
- 为什么要三次握手,而不是四次
- [三次握手连接阶段,最后一次 ACK 包丢失,会发生什么?](#三次握手连接阶段,最后一次 ACK 包丢失,会发生什么?)
- [TCP 的四次挥手(连接断开)](#TCP 的四次挥手(连接断开))
-
- [图解 TCP 四次挥手](#图解 TCP 四次挥手)
- 为什么连接的时候是三次握手,关闭的时候却是四次挥手?
- 为什么客户端的TIME-WAIT状态必须等待2MSL?
- 如果已经建立了连接,但是客户端出现故障了怎么办?
TCP
TCP 的核心特点
1.面向连接
TCP 要求通信双方在传输数据前通过三次握手 建立连接,结束后通过四次挥手释放连接,确保通信的可靠性和顺序性。
2.可靠传输
- 确认应答(ACK)与重传机制:接收方对收到的数据发送确认信号,发送方未收到 ACK 时自动重传。
- 数据顺序保证:通过序号和确认号字段确保数据按发送顺序重组和传递。
- 错误检测:利用校验和验证数据完整性,发现错误则触发重传。
3.全双工通信
支持双向数据传输,允许双方同时发送和接收数据,通过独立的发送/接收缓存实现高效交互。
4.面向字节流
将应用层数据视为无结构的字节序列传输,动态划分报文段以适应网络条件和接收方窗口大小。
5.流量控制
通过滑动窗口协议动态调整发送速率,避免接收方缓冲区溢出导致数据丢失。
6.拥塞控制
采用慢启动、拥塞避免、快速重传等算法,根据网络拥塞程度调整数据发送速率,保障整体网络稳定性。
7.网络适应性
设计上兼容异构网络环境(如带宽、延迟差异),通过动态机制应对网络故障和拓扑变化,确保端到端通信的健壮性。
TCP 与 UDP 特性对比
特性 | TCP | UDP |
---|---|---|
连接方式 | 面向连接 | 无连接 |
可靠性 | 可靠(重传、确认机制) | 不可靠(无确认机制) |
传输效率 | 较低(需建立连接) | 较高(直接发送数据报) |
适用场景 | 文件传输、实时性要求低 | 视频流、在线游戏 |
TCP 标志位
TCP 标志位的值代表了当前请求的目的。
-
SYN :发送/同步标志,用来 建立连接,和下面的第二个标志位 ACK 搭配使用。连接开始时,SYN = 1,ACK = 0,代表连接开始但是未获得响应。当连接被响应的时候,标志位会发生变化,其中 ACK 会置为 1,代表确认收到连接请求,此时的标志位变成了 SYN = 1, ACK = 1。
-
ACK :确认标志,标识 确认收到请求
-
PSH :表示 推送操作,就是指数据包到达接收端以后,不对其进行队列处理,而是尽可能的将数据交给应用程序处理
-
FIN :结束标志,用于 结束一个 TCP 会话
-
RST :重置复位标志,用于 复位对应的 TCP 连接
-
URG:紧急标志,用于保证 TCP 连接不被中断,并且督促中间层设备尽快处理
此外,还有两个序号:
- Sequence number(seq) :顺序号,发送数据包中的第一个字节的序列号,一般为小写的 seq。
- Acknowledge number(ack):确认号,响应前面的 seq,值为 seq+1,可以理解为期望下次发出的序列号为 seq+1;
TCP 的三次握手(建立连接)
TCP 三次握手概述
所谓三次握手(Three-way Handshake),是指 建立一个 TCP 连接时,需要客户端和服务器总共发送 3 个包。 三次握手的 目的是连接服务器指定端口,建立 TCP 连接, 并同步连接双方的顺序号和确认号并交换 TCP 信息。
举个栗子
公安局长王哥 和 陈某打电话
公安局:你好!陈某,听得到吗?(一次会话)
陈某:听到了,王哥,你能听到吗 (二次会话)
公安局:听到了,你过来自首吧 (开始会话)(三次会话)
通过这个例子我们可以知道三次会话的目的就是为了确保双方的连接正常,同理,TCP 三次握手也是这个过程,下面用图文形式来解释一下 TCP 三次握手。
图解 TCP 三次握手

最开始的时候客户端和服务器都是处于 CLOSED 关闭状态。主动打开连接的为客户端,被动打开连接的是服务器。
TCP 服务器进程先创建传输控制块 TCB,时刻准备接收客户进程的连接请求,此时服务器就进入了 LISTEN 监听状态
第一次握手:
TCP 客户进程也是先创建传输控制块 TCB,然后向服务器发出连接请求报文,这是报文首部中的同部位 SYN = 1,同时选择一个初始序列号 seq = x,此时, TCP 客户端进程进入了 SYN-SENT(同步已发送状态)状态。 TCP 规定,SYN 报文段(SYN = 1 的报文段)不能携带数据,但需要消耗掉一个序号。
第二次握手:
TCP 服务器收到请求报文后,如果同意连接,则发出确认报文。确认报文中应该 ACK = 1,SYN = 1,确认号是 ack = x+1,同时也要为自己初始化一个序列号 seq = y,此时,TCP 服务器进程进入 SYN-RCVD(同步收到)状态。 这个报文也不能携带数据,但是同样要消耗一个序号。
第三次握手:
TCP 客户端收到确认后,还要向服务器给出确认。确认报文的 ACK = 1,ack = y+1,自己的序列号 seq = x+1,此时,TCP 连接建立,客户端进入 ESTABLISHED(已建立连接)状态 。TCP 规定,ACK 报文段可以携带数据,但是如果不携带数据则不消耗序号。
为什么需要三次握手,而不是两次
主要有三个原因:
1.防止已过期的连接请求报文突然又传送到服务器,因而产生错误和资源浪费。
在双方两次握手即可建立连接的情况下,假设客户端发送 A 报文段请求建立连接,由于网络原因造成 A 暂时无法到达服务器,服务器接收不到请求报文段就不会返回确认报文段。
客户端在长时间得不到应答的情况下重新发送请求报文段 B,这次 B 顺利到达服务器,服务器随即返回确认报文并进入 ESTABLISHED 状态,客户端在收到 确认报文后也进入 ESTABLISHED 状态,双方建立连接并传输数据,之后正常断开连接。
此时姗姗来迟的 A 报文段才到达服务器,服务器随即返回确认报文并进入 ESTABLISHED 状态,但是已经进入 CLOSED 状态的客户端无法再接受确认报文段,更无法进入 ESTABLISHED 状态,这将导致服务器长时间单方面等待,造成资源浪费。
2.三次握手才能让双方均确认自己和对方的发送和接收能力都正常。
第一次握手:客户端只是发送处请求报文段,什么都无法确认,而服务器可以确认自己的接收能力和对方的发送能力正常;
第二次握手:客户端可以确认自己发送能力和接收能力正常,对方发送能力和接收能力正常;
第三次握手:服务器可以确认自己发送能力和接收能力正常,对方发送能力和接收能力正常;
可见三次握手才能让双方都确认自己和对方的发送和接收能力全部正常,这样就可以愉快地进行通信了。
3.告知对方自己的初始序号值,并确认收到对方的初始序号值。
TCP 实现了可靠的数据传输,原因之一就是 TCP 报文段中维护了序号字段和确认序号字段,通过这两个字段双方都可以知道在自己发出的数据中,哪些是已经被对方确认接收的。这两个字段的值会在初始序号值得基础递增,如果是两次握手,只有发起方的初始序号可以得到确认,而另一方的初始序号则得不到确认。
为什么要三次握手,而不是四次
因为三次握手已经可以确认双方的发送接收能力正常,双方都知道彼此已经准备好,而且也可以完成对双方初始序号值得确认,也就无需再第四次握手了。
- 第一次握手:服务端确认"自己收、客户端发"报文功能正常。
- 第二次握手:客户端确认"自己发、自己收、服务端收、客户端发"报文功能正常,客户端认为连接已建立。
- 第三次握手:服务端确认"自己发、客户端收"报文功能正常,此时双方均建立连接,可以正常通信。
三次握手连接阶段,最后一次 ACK 包丢失,会发生什么?
服务端:
- 第三次的 ACK 在网络中丢失,那么服务端该 TCP 连接的状态为 SYN_RECV, 并且会根据 TCP 的超时重传机制,会等待 3 秒、6 秒、12 秒后重新发送 SYN+ACK 包,以便客户端重新发送 ACK 包。
- 如果重发指定次数之后,仍然未收到 客户端的 ACK 应答,那么一段时间后,服务端自动关闭这个连接。
客户端:
- 客户端认为这个连接已经建立,如果客户端向服务端发送数据,服务端将以 RST 包(Reset,标示复位,用于异常的关闭连接)响应。此时,客户端知道第三次握手失败。
TCP 的四次挥手(连接断开)
建立 TCP 连接需要三次握手,终止 TCP 连接需要四次挥手
举个例子
张三和李四的对话
张三:好的,那我先走了
李四:好的,那你走吧
李四:那我也走了?
张三:好的,你走吧
图解 TCP 四次挥手

数据传输完毕后,双方都可释放连接。最开始的时候,客户端和服务器都是处于 ESTABLISHED 状态,然后客户端主动关闭,服务器被动关闭。
第一次挥手:
客户端发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN = 1,其序列号为 seq = m(等于前面已经传送过来的数据的最后一个字节的序号加 1),此时,客户端进入 FIN-WAIT-1(终止等待 1)状态。 TCP 规定,FIN 报文段即使不携带数据,也要消耗一个序号。
第二次挥手:
服务器端接收到连接释放报文后,发出确认报文,ACK=1,ack=m+1,并且带上自己的序列号seq=n,此时,服务端就进入了CLOSE-WAIT 关闭等待状态。 **TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。**这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
第三次挥手:
客户端接收到服务器端的确认请求后,客户端就会进入FIN-WAIT-2(终止等待2)状态 ,等待服务器发送连接释放报文,服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
第四次挥手:
客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=p+1,而自己的序列号是seq=m+1,此时,客户端就进入了TIME-WAIT(时间等待)状态 ,但此时TCP连接还未终止,必须要经过2MSL 后(最长报文寿命),当客户端撤销相应的TCB后,客户端才会进入CLOSED关闭状态 ,服务器端接收到确认报文后,会立即进入CLOSED关闭状态,到这里TCP连接就断开了,四次挥手完成。
为什么连接的时候是三次握手,关闭的时候却是四次挥手?
四次挥手:服务器在收到客户端(第一次)的FIN报文段后,可能还有一些数据要传输,所以不能马上关闭连接,但是会做出应答(第二次),返回ACK报文段。
接下来可能会继续发送数据,在数据发送完毕后,服务器会向客户端发送FIN报文(第三次),表示数据已经发送完毕,请求关闭连接。服务器的ACK和FIN一般都会分开发送,从而导致多了一次,因此一共需要四次挥手。
为什么客户端的TIME-WAIT状态必须等待2MSL?
主要有两个原因:
1.确保ACK报文能够到达服务端,从而使服务端正常关闭连接。
第四次挥手时,客户端第四次挥手的ACK报文不一定会到达服务端。服务端会超时重传FIN/ACK报文,此时如果客户端已经断开连接,那么就无法响应服务端的二次请求,这样服务端迟迟收不到FIN/ACK报文的确认,就无法正常断开连接。
MSL 是报文段在网络上存活的最长时间。客户端等待 2MSL 时间,即「客户端 ACK 报文 1MSL 超时 + 服务端 FIN 报文 1MSL 传输」,就能够收到服务端重传的 FIN/ACK 报文,然后客户端重传一次 ACK 报文,并重新启动 2MSL 计时器。如此保证服务端能够正常关闭。
如果服务端重发的 FIN 没有成功地在 2MSL 时间里传给客户端,服务端则会继续超时重试直到断开连接。
2.防止已失效的连接请求报文段出现在之后的连接中。
TCP 要求在 2MSL 内不使用相同的序列号。客户端在发送完最后一个 ACK 报文段后,再经过时间 2MSL,就可以保证本连接持续的时间内产生的所有报文段都从网络中消失。这样就可以使下一个连接中不会出现这种旧的连接请求报文段。或者即使收到这些过时的报文,也可以不处理它。
如果已经建立了连接,但是客户端出现故障了怎么办?
或者说,如果三次握手阶段、四次挥手阶段的包丢失了怎么办?如"服务端重发 FIN丢失"的问题
简而言之,通过定时器+超时重传机制,尝试获取确认,知道最后会自动断开连接。
具体而言,TCP 设有一个保活计时器。服务器每收到一次客户端的数据,都会重新复位这个计时器,时间通常是设置为 2 小时。若 2 小时还没有收到客户端的任何数据,服务器就开始重试:每隔 75 分钟发送一个探测报文段,若一连发送 10 个探测报文后客户端依然没有回应,那么服务器就认为连接已经断开了。