您现在的位置是:首页 >技术杂谈 >TCP协议网站首页技术杂谈

TCP协议

AAAAA_73 2023-05-20 20:00:02
简介TCP协议

TCP协议是一个很典型传输层协议。

TCP协议报文格式

在这里插入图片描述


可靠传输

可靠传输是 TCP 存在的初心!最核心的机制!

可靠传输的意思不是说100%可以传输成功,而是尽可能的传输,如果传输不过去,发送方可以知道自己传输失败,接收方有没有收到数据,会有个回应。

TCP 如何实现可靠传输:确认应答+超时重传

确认应答

确认应答指的是:接收方收到数据,会返回应答报文,ACK(acknowledge)报文。
在这里插入图片描述

TCP 报头中有一个序号字段和一个确认序号字段。
发送方,报头中序号是1,后面数据有1000个字节。
接收方,收到数据,返回的应答报文的报头中确认序号是1001。
那么发送方通过应答报文中的确认序号,就知道前面1000个字节已经成功传输了,接下来要传输 1001 往后的数据。

TCP 是针对数据的每个字节去编号的。在这里插入图片描述

‌超时重传

丢包

丢包是网络上非常常见的情况。

网络传输过程中,通过很多的路由器,交换机进行转发,这些网络设备转发能力是有上限的,当这中间某一个网络设备太忙了,要转发的数据太多了,这种情况下有些数据就会丢失。

  1. 数据包丢失

如果数据丢包了,接收方就不会返回应答报文。发送方接收不到应答报文,如果迟迟收不到应答报文,发送方就会重新发送这个数据,这就是 超时重传
在这里插入图片描述

  1. ACK丢失

如果应答报文也可能丢包,发送方也收不到应答报文,也会重发送数据,那么接收方就会收到两份一样的数据,但是没关系,TCP 会通过序号在接收缓冲区帮我们去重, 上层的应用程序不会读到重复的数据。
在这里插入图片描述

  1. 连续丢包

如果连续丢包,这种情况可能是网络出现了严重故障。

TCP 面对这种连续丢包的情况,也会重传,但是每次丢包都会延长超时等待的时间(TCP认为网络出问题了,重传大概率也不能成功,干脆摆烂)。

连续多次重传,都没收到应答报文,TCP 就会尝试重新连接,如果重连也失败,TCP 就会关闭连接, 放弃网络通信。

确认应答保证可靠性,如果出现丢包,超时重传作为补充。


连接管理机制

连接管理也一定程度上保证了可靠传输。
连接指的是通信双方,各自记住对方的信息。

三次握手

‌TCP 建立连接,三次握手

握手🤝,指的是通信双方进行一次网络通信。
三次握手,就是客户端和服务器通信三次,成功握手三次,才建立连接。

通信双方各自给对方发同步报文 SYN 和应答报文 ACK

在这里插入图片描述

过程:

第一次握手:客户端先给服务器发送一个 SYN
第二次握手:服务器收到后,将 ACK + SYN 一起返回给客户端。
第三次握手:然后客户端也返回给服务器 ACK

TCP 报头里,有6个特殊的bit位,默认是0,如果设为1,那么就代表目前是什么类型的报文。
ACK + SYN 就是第2位和第5位都为1。

为啥要三次握手:
投石问路!验证客户端和服务器各自的发送能力和接收能力是否正常。
三次握手就是确保双方能正常通信,才建立连接。

四次挥手

‌TCP 断开连接,四次挥手

通信双方通过四次网络通信,来断开连接。

通信双方,各自给对方发送一个结束报文 FIN,再各自返回应答报文 ACK
与建立连接不一样,客户端和服务器都可以主动断开连接。

在这里插入图片描述
过程:
以客户端断开连接为例。
第一次挥手:客户端先向服务器发送 FIN
第二次挥手:服务器向客户端返回 ACK
第三次挥手:服务器也向客户端发送 FIN
第四次挥手:客户端也向服务器返回 ACK

服务器返回 ACK 和发送 FIN 是有概率合并为一条报文的,但是通常情况下,是不能合并的。

三次握手中服务器发送的 ACKSYN 是可以 100% 合并的。

四次挥手为什么不能合并呢?

三次握手: ACKSYN 是同一时机触发的(都是系统内核完成的)。
四次挥手: ACKFIN 不是同一时机触发的。
ACK 是系统内核完成的,会在收到 FIN 的时候第一时间返回。
FIN 是由应用程序的代码控制的,在调用 socketclose 方法时,才会发送。


批量传输

滑动窗口

TCP 协议保证了可靠性,同时也降低了效率。
每次发送数据,都要等待ACK,效率较低。

滑动窗口是用来弥补TCP效率 的机制。
批量发送数据,一次发多条数据,一次等多条ACK。

在这里插入图片描述

批量发四条数据,再去等待ACK,然后每次收到一条ACK,就立即发送下一条数据,这样就可以同时等待四条ACK,而不是等一条,发一条了。
使用一份时间,等待多条ACK,总的等待时间缩短,效率也就提高了。

这个批量传输,称为滑动窗口。
窗口大小:同时等待ACK的数量。
滑动:收到一个ACK就立即发下一条。

在这里插入图片描述

这个图可以看到,主机A批量发送了四条数据,同时等待四个 ACK
当 主机A 收到 主机B 返回的 ACK 后,立即发送下一条数据,并且窗口向后滑动。
如果收到 ACK 的速度非常快,这个窗口就会快速的往后滑动。

批量发送的过程中,丢包了会发生什么?

  1. 数据包成功送达,ACK丢包

这种情况没关系,对传输可靠性没有任何影响。
确认序号的含义,表示该序号之前的序号的数据都已经收到了。
这说明前一个ACK丢了,后一个也能代表前一个应答。

在这里插入图片描述

确认序号为 3001 和 4001 的 ACK 都丢了,但是主机A收到 5001 这个 ACK 时,说明之前传输的数据 主机B 都收到了。
但是如果 6001 最后一个 ACK 丢了,主机A 迟迟没收到 ACK,就会触发超时重传。

  1. 数据包丢失,没有成功送达

在这里插入图片描述

当发送端收到3个同样的ACK,就会重新发送接收端索要的数据。
这种重传机制,没有冗余操作,不会发送重复的数据,数据丢了才会重传,这个重传也称为 快速重传。

滑动窗口和快速重传,是在批量传输大量数据时,才会触发的机制。
如果只是传输少量,低频数据的时候,还是一条一条发,采用 确认应答和超时重传机制


流量控制

滑动窗口,窗口越大,批量传输的数据越多,同时等待的ACK越多,整体速度就越快。
但是不能让这个窗口太大,因为如果发的太快,接收端处理不过来,把接收端的接收缓冲区放满了,数据就会丢失,这样还不如发慢一点呢。

流量控制,本质上就是让接收端来限制发送端的传输速度。这也是保证可靠性的机制。

在这里插入图片描述

如何进行流量控制?

在 TCP 报文中有一个字段表示窗口大小,当这个报文为 ACK 报文时,这个字段就会生效。
这个字段的值就是建议发送端批量传输时的窗口大小。

接收方如何计算窗口大小?

接收缓冲区的剩余空间,作为窗口大小。

注意:

发送端第一次传输数据时不知道接收端缓冲区的情况,不会批量发送。

窗口探测:

接收端接收缓冲区满了之后,发送端会暂停发送,但是会隔一段时间发一个窗口探测报文,来检测接收端的状态。


拥塞控制

滑动窗口的大小取决于流量控制和拥塞控制。
流量控制是通过接收端的处理能力来调整窗口大小。

拥塞控制是通过预估路径的传输能力来调整窗口大小。

发送端给接收端传输数据,会经过很多的中间节点(路由器/交换器),这些设备的传输能力是有限的,当中间任意一个节点传输能力达到上限,就会出现大量丢包。

如何进行拥塞控制?

因为通信双方之间,有很多中间节点,每次传输的路径也不完全相同,所以无法直接给出合适的窗口大小。只能通过实验,来找到一个合适的发送速率。

一开始,拥塞窗口较小,如果没有丢包,拥塞窗口指数级增长,达到一个阈值,就转为线性增长,如果出现大量丢包(网络拥堵),就立即调小窗口,重复这个过程。

在这里插入图片描述

拥塞窗口:

这是发送端进行实验得到的,用来衡量通信双方中间节点的传输能力。
发送端将 拥塞窗口 和 接收端返回的 ACK 中的窗口大小做比较,取较小值作为实际发送的窗口大小

拥塞控制是想尽可能快的传输数据,但是又要避免网络拥堵。


应答机制

延迟应答

延迟应答的目的是提高效率。
延迟应答指的是接收端收到数据,等一会才发送 ACK。

如果立即发送ACK,窗口大小可能比较小。
等一会再发,可能接收端已经处理完数据了,接收缓冲区剩余空间变大,返回的窗口大小就比较大。

延迟应答的方式:

  • 数量限制:每隔N个包就应答一次;
  • 时间限制:超过最大延迟时间就应答一次
    在这里插入图片描述

捎带应答

捎带应答是在延迟应答的基础上实现的,很多时候服务器与客户端是双向通信,比如客户端给服务器说了 “How are you”,服务器也会给客户端回一个 “Fine,thank you”。

这时候服务器返回的 ACK 就可以搭顺风车,与服务器回应的 “Fine,thank you” 一起发送给客户端。


粘包问题

什么是粘包问题

首先要知道,这个 “包” 是 应用层数据包
TCP是 面向字节流 的,而且没有 UDP报头中 报文长度 这样的字段。
所以当 A 给 B 连续发了多个应用层数据包后,这些数据都堆在了 B 的接收缓冲区中,B 的应用层看到是一连串的字节数据。
那么 B 就难以区分这一连串的字节数据,从哪部分到哪部分,是一个完整的应用层数据包。

如何避免粘包问题

明确应用层数据包之间的边界,方法有很多。

  1. 可以在包头位置,约定一个数据包长度的字段,就知道了这个包的数据的结束位置。
  2. 可以约定使用明确的分隔符,只要分隔符不与正文冲突,就可以很好的区分两个包。

TCP异常情况

进程中止

进程虽然中止了,但是 TCP 连接还在,会正常进行四次挥手断开连接。

主机关机

会先关闭所有进程,也会进行四次挥手,但是可能还没挥完,向对端发送 FIN 了, 还没等到对端的 ACKFIN ,就关机了。

对端多次发送 FIN ,也没有收到 ACK 回应,就会尝试重置连接,重置连接失败,就会释放连接。

主机掉电/网线断开

这种情况非常突然,连向对端发送 FIN 的机会都没有。

分两种情况考虑:

  1. 对端是发送端

对端发送数据,接收不到 ACK,就会超时重传,重复多次也没收到 ACK,就会尝试重置连接,重置连接失败,就会释放连接。

  1. 对端是接收端

对端是接收端的情况下,对端无法立即感知到我们出现了异常.

对于这种情况,TCP内置了一个保活定时器,定期发送一个心跳包,如果多次没有回应,就释放连接。


风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。