TCP 协定全称为:Transmission Control Protocol
,是一种面向链接、保障数据传输平安、牢靠的数据传输协定。为了确保数据的牢靠传输,不仅须要对收回的每个字节进行编号确认,还须要验证每一个数据包的有效性。每个 TCP 数据包是关闭在 IP 包中的,每个一 IP 包的前面紧跟着的是 TCP 头,TCP 报文格式如下:
源端口和目标端口字段
- TCP 源端口(Source Port):源计算机上的应用程序的端口号,占 16 位。
- TCP 目标端口(Destination Port):指标计算机的应用程序端口号,占 16 位。
序列号字段
CP 序列号(Sequence Number):占 32 位。它示意本报文段所发送数据的第一个字节的编号。在 TCP 连贯中,所传送的字节流的每一个字节都会按程序编号。当 SYN 标记不为 1 时,这是以后数据分段第一个字母的序列号;如果 SYN 的值是 1 时,这个字段的值就是初始序列值(ISN),用于对序列号进行同步。这时,第一个字节的序列号比这个字段的值大 1,也就是 ISN 加 1。
确认号字段
TCP 确认号(Acknowledgment Number,ACK Number):占 32 位。它示意接管方冀望收到发送方下一个报文段的第一个字节数据的编号。其值是接管计算机行将接管到的下一个序列号,也就是下一个接管到的字节的序列号加 1。
数据偏移字段
TCP 首部长度(Header Length):数据偏移是指数据段中的“数据”局部起始处间隔 TCP 数据段起始处的字节偏移量,占 4 位。其实这里的“数据偏移”也是在确定 TCP 数据段头局部的长度,通知接收端的应用程序,数据从何处开始。
保留字段
保留(Reserved):占 4 位。为 TCP 未来的倒退预留空间,目前必须全副为 0。
标记位字段
- CWR(Congestion Window Reduce):拥塞窗口缩小标记,用来表明它接管到了设置 ECE 标记的 TCP 包。并且,发送方收到音讯之后,通过减小发送窗口的大小来升高发送速率。
- ECE(ECN Echo):用来在 TCP 三次握手时表明一个 TCP 端是具备 ECN 性能的。在数据传输过程中,它也用来表明接管到的 TCP 包的 IP 头部的 ECN 被设置为 11,即网络线路拥挤。
- URG(Urgent):示意本报文段中发送的数据是否蕴含紧急数据。URG=1 时示意有紧急数据。当 URG=1 时,前面的紧急指针字段才无效。
- ACK:示意后面的确认号字段是否无效。ACK=1 时示意无效。只有当 ACK=1 时,后面的确认号字段才无效。TCP 规定,连贯建设后,ACK 必须为 1。
- PSH(Push):通知对方收到该报文段后是否立刻把数据推送给下层。如果值为 1,示意该当立刻把数据提交给下层,而不是缓存起来。
- RST:示意是否重置连贯。如果 RST=1,阐明 TCP 连贯呈现了严重错误(如主机解体),必须开释连贯,而后再从新建设连贯。
- SYN:在建设连贯时应用,用来同步序号。当 SYN=1,ACK=0 时,示意这是一个申请建设连贯的报文段;当 SYN=1,ACK=1 时,示意对方批准建设连贯。SYN=1 时,阐明这是一个申请建设连贯或批准建设连贯的报文。只有在前两次握手中 SYN 才为 1。
- FIN:标记数据是否发送结束。如果 FIN=1,示意数据曾经发送实现,能够开释连贯。
窗口大小字段
窗口大小(Window Size):占 16 位。它示意从 Ack Number 开始还能够接管多少字节的数据量,也示意以后接收端的接管窗口还有多少残余空间。该字段能够用于 TCP 的流量管制。
TCP 校验和字段
校验位(TCP Checksum):占 16 位。它用于确认传输的数据是否有损坏。发送端基于数据内容校验生成一个数值,接收端依据接管的数据校验生成一个值。两个值必须雷同,能力证实数据是无效的。如果两个值不同,则丢掉这个数据包。Checksum 是依据伪头 + TCP 头 + TCP 数据三局部进行计算的。
紧急指针字段
紧急指针(Urgent Pointer):仅当后面的 URG 管制位为 1 时才有意义。它指出本数据段中为紧急数据的字节数,占 16 位。当所有紧急数据处理完后,TCP 就会通知应用程序复原到失常操作。即便以后窗口大小为 0,也是能够发送紧急数据的,因为紧急数据毋庸缓存。
可选项字段
选项(Option):长度不定,但长度必须是 32bits 的整数倍。
TCP 建设连贯
TCP 建设连贯须要三个步骤,也就是大家熟知的三次握手。下图了失常情景下通过三次握手建设连贯的过程:
-
A 机器收回一个数据包
SYN
设置为 1,示意心愿建设连贯。这个包中的假如 seq 为x
。- 机器 A 发送
SYN
数据包后,会进入SYN_SENT
状态
- 机器 A 发送
-
B 机器收到 A 发送的
SYN
数据后,响应一个数据包将SYN
和ACK
设置为 1,假如这个响应包的序列号为y
,同时冀望下一次收到的数据库的序列为x+1
- B 回复响应包后,进入
SYN_RECD
状态
- B 回复响应包后,进入
-
A 收到 B 的响应包后,对响应包做应答将
ACK
标记设置为 1,序列号为x + 1
,冀望下一次收到的数据包的序列号为y+1
- A 机器和 B 机器连贯建设胜利
TCP 三次握手抓包验证
认为验证三次握手是否形容正确,在下应用 Wireshark
进行抓包验证。首先应用 ping
命令获取 www.baidu.com
的 ip 地址:
正在 Ping www.a.shifen.com [183.232.231.174] 具备 32 字节的数据:
来自 183.232.231.174 的回复: 字节 =32 工夫 =16ms TTL=54
来自 183.232.231.174 的回复: 字节 =32 工夫 =16ms TTL=54
来自 183.232.231.174 的回复: 字节 =32 工夫 =16ms TTL=54
183.232.231.172 的 Ping 统计信息:
数据包: 已发送 = 3,已接管 = 3,失落 = 0 (0% 失落),往返行程的预计工夫(以毫秒为单位):
最短 = 16ms,最长 = 16ms,均匀 = 16ms
以上输入显示 www.baidu.com
的 ip 地址:183.232.231.174
,而后应用 Wireshark
的过滤器仅显示与 www.baidu.com
通信的 tcp
数据包:
ip.src_host == "183.232.231.174" or ip.dst_host == "183.232.231.174" and tcp
应用 Wireshark
抓包剖析后,验证 TCP 失常连贯三次握手与上节形容的统一。
为什么是三次握手?
为什么是三次握手?三次握手次要有两个目标:信息对等 和避免超时。
信息对等
两台机器通信时都须要确认四个信息:
- 本人发报文的能力
- 本人收报文的能力
- 对方发报文的能力
- 对方收报文的告诉
第一次握手
第一次握手 A 机器向 B 机器发送 SYN
数据包,此时只有 B 机器能确认 本人收报文的能力 和对方发报文的能力。
一次握手实现 B 机器可能确认的信息有:
- [x] B 机器收报文的能力
- [x] A 机器发报文的能力
第二次握手
每二次握手后 B 响应 A 机器的 SYN
数据包,此时 A 机器就能确认:本人发报文的能力 、 本人收报文的能力 、 对方发报文的能力 、 对方收报文的能力
二次握手实现 A 机器可能确认的信息有:
- [x] A 机器发报文的能力
- [x] A 机器收报文的能力
- [x] B 机器发报文的能力
- [x] B 机器收报文的能力
第三次握手
每三次握手后 A 应答 B 机器的 SYN + ACK
数据包,此时 B 机器就能确认:本人发报文的能力 、 对方收报文的能力
二次握手实现 A 机器可能确认的信息有:
- [x] B 机器发报文的能力
- [x] A 机器收报文的能力
至此通过三次握手 A、B 机器就能做到信息对等,单方都能确认本人和对方的收、发报文的能力,最初不便了解将信息对等制作成一个小表格:
避免超时
三次握手除了保障 信息对等 也是了避免申请超时导致 脏连贯。TTL 网络报文的生存往往会超过 TCP 申请超时工夫,如果两次握手就能创立连贯,传输数据并开释连贯后,第一个超时的连贯申请才达到 B 机器,B 机器 会认为是 A 创立新连贯的申请,而后确认批准创立连贯。因为 A 机器的状态不是SYN_SENT
,所以会间接抛弃了 B 的确认数据,导致 B 机器单方面的创立连贯结束。
如果是三次握手,则 B 机器收到连贯申请后,同样会向 A 机器确批准创立连贯,但因为 A 不是 SYN_SENT
状态,所以 A 机器 不会回复 B 机器确认创立连贯申请,而 B 机器到一段时间后因为长时间没有收到确认信息,最终会导致连贯创立失败,因而不会呈现脏连贯。
TCP 断开连接
TCP 是全双工通信,单方都能作为数据的发送方和接管方,但 TCP 会有断开的时候。TCP 建设连贯须要三次握手而断开连接却要四次,如图所示为 TCP 断开连接四次挥手过程:
- A 机器发送敞开数据包将
FIN
设置为 1,假如序列号为u
,发完敞开数据包后此时 A 机器解决FIN_WAIT_1
状态 - B 收到敞开连贯申请后,告诉利用程序处理完剩下的数据
- B 响应 A 的敞开连贯申请,将
ACK
标记设置为 1,seq 为v
,ack 为u+1
,随后 B 机器处于CLOSE_WAIT
状态 - A 收到应答后,处于
FIN_WAIT_2
状态,持续期待 B 机器的FIN
数据包 - B 解决好现场后,被动向 A 机器发送数据包,并将
FIN
和ACK
标记设置为 1,seq 为w
,ack 为u+1
,随后处于LAST_WAIT
状态期待 A 机器的应答 - A 机器收到
FIN
数据包后,随后发送ACK
数据包,seq 为u+1
,ack 为w+1
, 此时 A 机器解决TIME_WAIT
状态 - B 机器收到
ACK
响应包后,进行CLOSED
状态,连贯失常敞开 -
A 机器在
TIME_WAIT
状态期待2MSL
后,也进入CLOSEED
状态,连贯敞开什么是 2MSL:MSL 是 Maximum Segment Lifetime 英文的缩写,中文能够译为“报文最大生存工夫”,
2MSL 即两倍的 MSL
四次挥手断开连接能够用更形象的形式来表白:
- 男生:咱们离别吧。
- 女生:好的,我须要去家里把货色拾掇完,再发消息给你。(此时男生不能再拥抱女生)
- 。。。,一个小时后
- 女生:我拾掇完了,离别吧(此时女生也不能再拥抱男生)
- 男生:好的(此时单方约定一段时间后,才能够别离找新的对象)
TCP 四次挥手抓包验证
抓包过程与与三次握手抓包过程统一,这里不形容。间接看拜访后抓包的截图:
- 第一个包是由
192.168.1.6
这台机器(也就是客户机),发送了一个FIN
包,seq 为80
,ack 为2782
- 第二个包由
183.232.231.174
(服务器),对192.168.1.6
这台机器(也就是客户机)发送了一个ACK
包,seq 为2782
,ack 为81
- 第三个包由
183.232.231.174
(服务器),对192.168.1.6
这台机器(也就是客户机)发送了一个ACK
和FIN
包,seq 为2782
,ack 为81
- 第四个包由
192.168.1.6
,向服务器响应了一个ACK
包,seq 为81
,ack 为2783
四次挥手流程与咱们形容的统一。
TIME_WAIT 状态
被动要求敞开的机器(机器 A)示意收到对方的 FIN
报文后,并发送出 ACK
报文后,进行 TIME_WAIT
状态,期待 2MSL
后进行 CLOSED
状态。如果在 TIME_WAIT_1
时收到FIN
标记和 ACK
标记报文时,能够间接进入 TIME_WAIT
状态,而无需进入 TIME_WAIT_2
状态。
为什么要有 TIME_WAIT
确认被动敞开(机器 B)可能顺利进入 CLOSED
状态
如果 A 机器发送最初一个 ACK
后,但因为网络起因 ACK
包未能达到 B 机器,此时 B 机器通常会认为 A 机器 没有收到 FIN+ACK
报文,会重发一次 FIN+ACK
报文。如果 A 机器 发送最初一个 ACK
后,自私的敞开连贯进入 CLOSED
状态,就可能导致 B 无奈收到 ACK
报文,无奈失常敞开。
避免生效申请
TIME_WAIT 状态能够避免已生效的申请包与失常连贯的申请数据包混同而产生异样。因为 TIME_WAIT 状态无奈真正开释句柄资源,在此期间,Socket 中应用的本地端口在默认状况下不能再被应用。
CLOSE_WAIT 状态
被动敞开的机器(机器 B)在收到对方发送的,FIN
报文后,马上回复 ACK
报文,进入 CLOSE_WAIT
状态。告诉应用程序,解决剩下的数据,开释资源。
欢送关注我的公众号:架构文摘,取得独家整顿 120G 的收费学习资源助力你的架构师学习之路!
公众号后盾回复
arch028
获取材料: