详解TCP协议多种机制
1.TCP报文格式
为了方便后续各位深入理解TCP机制,我们有必要先了解一下TCP的报文格式,首先我们先来看如下图
第四行那六个单词分别有不同的作用,初始为0,无作用,置为1即代表不同作用,具体后面会介绍。
我们后面要介绍的各种机制,实际都与这些息息相关,OK,话不多说,我们首先来介绍第一个机制——-——
可靠性机制
2.可靠性机制
可靠性机制主要是由确认应答,超时重传,连接管理(重中之重之重之重之重),拥塞控制实现的,下面我们来一一介绍。
2.1确认应答
详细解析:发送端发送数据都会根据数据生成一个序号,然后把这个序号写入TCP报文头中,也就是上面报文图的第二行,接收端在接收这条数据之后,会将序号加1然后填入确认序号,并将ACK 置为1表示是对之前数据的应答,也是按照TCP报文格式发送的,那么发送端在接收到这个报文之后就知道接收端确实接收到了之前的数据,就会放心的去继续发送数据,然后接收端继续发送ACK应答,如此循环直到数据发送完毕。
这么看确实比UDP好不少,UDP管你收没收到,发完就润。
补充:注意区分应答和响应
应答:在传输层层面,只是一个标记,虽然是按照TCP报文格式发送的,但是数据项为空。
响应:在应用层层面,是针对客户端请求计算出来的结果,包含真实数据。
白话版:想象一下你跟女生激情告白,写了三千字小作文,第一种情况:女生看完扣了个1表示消息收到了,但是没有任何表态,仅此而已。
第二种情况:女生热泪盈眶,写了三万字小作文明确的拒绝了你。哈哈。。。
那么应答就是扣了一1
响应则是三万字小作文,针对你的要求(在一起)给出了明确的结果(拒绝)。
2.2超时重传
介绍;ACK是一个确认信号,ACK置为1即表示你刚才发的数据我都收到了。
所谓ACK应答也即是把ACK置为1的TCP报文。
详细解析:数据在传输过程中要经过很多网络设备,比如:路由器,交换机,运营商网络等等,,
在此过程如果任何一个设置出问题,比如太阳耀斑,地球爆炸,网络中断,本次数据传输就会出现超时现象(规定时间内没有拿到刚发送数据的ACK应答)
那么设计TCP协议的大牛是如何处理这个问题呢,啊听名字就知道,如果确定出现超时现象了我就重新发一次数据。
那会不会发送端成功发送了数据1-1000,接收端也接收了,但是接收端发送ACK应答时出现了丢包,导致发送端判定为超时了重新发了数据1-1000,那么接收端会接收两个数据1-000吗,答案是不会,接收端会根据报文中序号来判断是否接收过这些数据,如果发现接收过就舍弃第二次收到的数据1-1000,然后重新发送数据1-1000ACK应答.
2.3连接管理(重中之重之重之重之重之重之重)
介绍:上面讲的都是发送端和接收端数据传输之间的设计,那发送端和接收端是如何建立连接呢,大牛对于建立连接又有怎样的设计呢😮。
2.3.1三次握手
概要:
连接建立时:三次握手
连接断开时:四次挥手
(礼貌这一块👍)
先看图:
SYN就是握手字符,我们前面说SYN等都是置为0的,不发挥作用,那么当SYN置为1就表示我想要和你建立连接,是一个握手信号。
ACK前面已经说过了不赘述。
那么现在我们来看图说话吧!
第一步: 首先发送端 发送了一个SYN为1的TCP报文表示我想和你建立连接,接收端同意建立连接(不然怎么传数据),这表示发送端的发送能力没有问题。
第二步:接收端发送了一个ACK为1 和SYN为1的TCP报文,ACK为1表示我收到了你的连接请求,SYN为1表示我也跟你建立连接,这表示接收端的接收能力和发送能力没有问题。
第三步:发送端再发送一个ACK为1的TCP报文,表示我也收到了你的连接请求。这表示发送端的接收的能力没有问题。
如此大功告成!!!发送端和接收端就可以开启没羞没臊的数据传输生活辣!
2.3.2四次挥手
说完了三次握手,我们再来谈四次挥手,也就是数据传输完毕之后是如何断开连接的呢?
我们还是先看图:
补充:
FIN就是结束字符,FIN置为1就表示关闭连接的请求,
为什么叫FIN?就是取了finish(完成,结束)前三个字符而已。
(不知道这个就觉得很高大上,了解了其实也就那么回事,很多事都是这样,装深沉这一块👍)
看图说话!
第一步:当发送端数据传输完毕之后就会发送一个FIN置为1的TCP报文,表示我想断开连接了。
第二步:接收端收到之后回一个ACK置为1的报文表明我收到了你的断开请求。
第三步:接收端也发送一个FIN置为1的报文表示我也想断开连接。
第四步:发送端再回一个ACK为1的报文,表示我也收到了你的断开请求。
(到此为止,双方都进行一次告别并得到对方的ACK应答,连接就断开了。。。。我知道天高任鸟飞,也知话说三遍淡如水,从此山水一程,再不相逢嘤嘤嘤)
那么有人就要问了!明明都是一个端发两条,怎么握手时就可以SYN跟ACK合在一起发,分手时FIN跟ACK怎么就得单独发呢!社交的手腕吗?!
别急,其实说到底还是为了保证数据传输的完整性和安全性:
详解:1.当发送端发送断开请求后,接收端可能还有一些数据没有发送给接收端,但是没关系,我可以先ACK应答,再去发送没发完的数据,确定发完之后我再对从容的对发送端发送关闭连接请求,然后发送端ACK应答,然后彻底关闭连接请求。(三次握手时候就没什么好顾虑的,光棍一条,你说连那就连)
2.从TCP状态机的角度看也是不能将FIN和ACK合在一起的。一图胜千言:
我们可以明确看到服务器在发送ACK报文跟FIN保文的状态是完全不一样的,如果将FIN和ACK合并,会使状态机逻辑变得复杂,难以准确维护连接关闭的状态和流程。(三次握手怎么可以?因为三次握手状态转变的条件就是收到一条ACK+SYN的报文,哈哈。。。还不明白的建议参考刘晓燕老师解释英语语法问题)
2.4拥塞控制
解析:数据在传输时,不是直接从我这发送到你那,中间会经历很多网络设置(交换机,路由器等等),而网络状况也不是永远稳定的,当网络波动时,如果不加干预发送端发送量(不是干预网络),就可能造成阻塞和超时。于是大牛就创造一个状态变量:拥塞窗口。
当网络出现波动时,拥塞窗口大小就会下降(置为1),而发送端窗口大小=min(本机拥塞窗口大小,对端滑动窗口大小),所以就显而易见了,拥塞窗口大小置为1时一定比对端滑动窗口小,然后发送端窗口大小就降了下来,那么网络波动对于数据传输的影响也就小了下来。
拥塞窗口值具体如何调整?
第一步 :数据刚开始传输时把拥塞窗口的值调到很少,比如1.
第二步:如果接收到ACK应答就表示当前窗口大小没有问题,然后就调大窗口大小
第三步:到达阈值(刚开始期望的窗口最大值)之前以指数形式增大,到达阈值后,以1为步长进行增大。
第四步:当增大到一定程度发生丢包情况后,就证明网络阻塞了(窗口太大了),这时就把窗口大小重新调为1,同时重置新的阈值二(当前窗口大小一半)
如此循环往复,动态调整。。。
3.效率机制
效率机制主要是由滑动窗口,流量控制,延迟应答实现的,接下来我们也是一一介绍。
3.1滑动窗口
滑动:指发送端在接收到ACK应答后把缓冲区中应答过的数据移除,并把后续要发的数据纳入缓冲区。
窗口:发送端无需接收ACK应答就能继续发送数据的最大值
在数据传输的过程中,如果只是一段一段的发那效率就太低了,所以滑动窗口说白了就是集中发送数据,用来提高效率。
我们再来详细解析一下滑动窗口是如何运作的:
解析:发送端将当前窗口要发送的数据分成几段,然后集中发送到接收端,每收到一段数据的ACK应答,就将那段数据移出缓冲区,然后纳入新的未发送的数据到缓冲区,纳入数据大小==已收到ACK应答数据的大小。
场景:我是一个发送端,我要发送1-100的数据,我的窗口大小是20,建立连接后,我纳入了1-20的数据到缓冲区,然后分成四段,集中发送了出去,当我收到1-5数据的ACK应答后,我将1-5数据移出缓冲区,然后将20-25纳入进来,循环往复,直到数据全部发送完毕。
还有疑惑的我只能上图了:
一看图你就直到为什么叫滑动窗口了吧😄
异常情况1:发送端数据已经被接收端接收,但是返回的ACK应答出现丢包事件。
如何处理呢?啊没关系发送端会继续发送数据,只要收到了后面的ACK应答,就算前面没收到也默认接收端接收到了。
场景一:发送端发送了1-100的数据,接收端收到了,但是返回的ACK应答丢包了,发送端会继续发送100-200的数据,发送端只要收到了100-200的ACK应答,就明白1-100的数据接收端也接收到了,因为如果前面的没收到,接收端就会在本次ACK应答确认序号字段中告诉发送端。
场景二:当别人问你什么学历,你只要把大学毕业证亮出来,别人就不会问你上过高中没你上过初中没,一个意思。
异常情况2:当发送端发送的一段数据出现丢包时,会如何处理呢?
首先接收端会将发送端发送成功的数据缓存起来,然后等到缺失数据重发成功后,会按照顺序将数据组织好,再去ACK最新的确认序号。
3.2流量控制
解析:窗口的大小并不是固定的,更不可能无限大(不然就发送数据这一方面和UDP有啥区别,都是一口气全发),实际上,它是根据接收端接收能力动态调整的。如何实现呢?就是接收端在发送ACK报文时,在“窗口大小”这个字段填入当前可处理数据的最大值,发送端根据这个调整窗口容量大小。确保我每次发送的数据你都能处理,如此就保证了传输效率。(就像给人喂饭一样,我确保我喂的每一口你都正好能吃下,喂多了你噎着当误吃饭,喂少了浪费时间)
补充:窗口大小=min(本机拥塞窗口大小,对端滑动窗口大小)
流量控制是控制窗口大小的一个手段,但并不唯一,上面的拥塞控制也有着类似的作用,
3.3延迟应答
解析:在数据传输时,如果接收端每收到一条数据就发个ACK应答那效率也很低,毕竟你ACK一次发送端还要看一次确认序号之类的,那么接收端每隔几端数据(一般是2)应答一次,或者每隔一个固定时间(一般是500ms)应答一次,就提高了数据传输效率,这就是延迟应答。
4优化机制
4.1捎带应答
解析:当接收端给发送端发送响应时,如果正好也要向发送端ACK应答一下,那么两个报文就有可能合并为一个,这样就减少了通讯次数,降低网络开销,还提高了效率。
补充:还是要注意区分一下,ACK应答是传输层,发送响应是应程序层面的。
5.粘包问题
图:
5.1产生原因
发送端原因:TCP是面向流的协议,五消息边界,发送端为了提高效率,可能会将多个小数据联合成一个大数据发送(例如1-5,5-10合并成1-10,10-15,15-20合并为10-20)。
接收端原因:未能及时从接收端缓冲区读取数据,导致多个数据包累积在缓冲区,等接收端读取时将多个数据包看作一个打包(1-10,10-20看作1-20)
5.2造成影响
接收端无法正确识别每个数据包的边界,最终可能导致数据解析错误,使得应用程序获取到错误的数据。
5.3解决方法
方法一:可以约定一个分隔符作为一条消息的边界
方法二:在应用层协议中商定定义一个字段用来专门表示本条消息的长度。(例如TCP报文中的首部长度,虽然表示的不是整条消息长度,但根据首部长度也能推断出数据长度,那TCP为什么不直接设置整条消息长度呢?因为有选项字段长度是可变的,设整条消息长度推断不出准据数据长度,但首部长度可以)
6完结撒花
小白执笔,如有错误欢迎欢迎热烈欢迎指😃