详解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的报文,哈哈。。。还不明白的建议参考刘晓燕老师解释英语语法问题)
3.效率机制
效率机制主要是由滑动窗口,流量控制,延迟应答实现的,接下来我们也是一一介绍。
3.1滑动窗口
滑动:指发送端在接收到ACK应答后把缓冲区中应答过的数据移除,并把后续要发的数据纳入缓冲区。
窗口:发送端无需接收ACK应答就能继续发送数据的最大值
在数据传输的过程中,如果只是我发一条你回一个ACK应答然后我在发那效率就太低了,所以滑动窗口说白了就是集中发送数据,用来提高效率。
3.1.1补充
值得注意的是,集中发送数据和前文我们介绍的确认应答并不矛盾,因为确认应答只是说我会发送对之前数据的ACK应答,并不意味着我对于收到的每一条数据都ACK应答。
清除了这一误区,我们再来详细解析一下滑动窗口是如何运作的:
解析:发送端将当前窗口要发送的数据分成几段,然后集中发送到接收端,每收到一段数据的ACK应答,就将那段数据移出缓冲区,然后纳入新的未发送的数据到缓冲区,纳入数据大小==已收到ACK应答数据的大小。
场景:我是一个发送端,我要发送1-100的数据,我的窗口大小是20,建立连接后,我纳入了1-20的数据到缓冲区,然后分成四段,集中发送了出去,当我收到1-5数据的ACK应答后,我将1-5数据移出缓冲区,然后将20-25纳入进来,循环往复,直到数据全部发送完毕。
还有疑惑的我只能上图了:
一看图你就直到为什么叫滑动窗口了吧😄
3.1.2补充
窗口的大小并不是固定的,更不可能无限大(不然就发送数据这一方面和UDP有啥区别,都是一口气全发),实际上,它是根据接收端接收能力动态调整的。如何实现呢?就是接收端在发送ACK报文时,在“窗口大小”这个字段填入当前可接受数据的最大接收值,发送端根据这个调整窗口容量大小。
异常情况1: