TCP十大机制

TCP八大核心机制:

1:确认应答机制

TCP的可靠传输是怎么做到可靠的;尽可能把数据传输过去;如果传输不过去;至少对方是知道的。而确认应答是实现可靠传输的最核心机制。
确认应答:比如;A给B发一个消息;B收到之后就会返回一个应答报文(ACK);A收到应答报文就知道刚才的数据已经顺利的到达B。但是数据发送是可能出现后发先至;因为两个主机路线可能有多条;转发的路由器交换机也有很多可能;会出现后面发的消息先到;如果不处理可能造成歧义。(我们得知道这个ack是回复哪条的;才知道它到了)
在这里插入图片描述
处理:针对传输数据和应答报文进行编号;就算乱序也能通过这个序列号区分当前应答报文是针对哪个数据进行。
这个序列号就是报头里的:任何一条数据(包括应答报文)都是有序列号;确认序号是只有应答报文有(普通报文的确认序号无意义);确认我是针对哪条消息的回复(比如我这里约坤哥打球有一个序号;坤哥的响应报文就会有一个确认序号说是针对我的约打球这条消息回复);应答报文的序号仅仅是一个身份标识。

在这里插入图片描述
在这里插入图片描述
怎么区分一条报文是不是应答报文
个位标志:如果ACK这个标志为1;表示是应答报文;如果是0则不是应答报文
在这里插入图片描述
实际上的TCP序号并不是简单的上面1,2这种方式编号,我们TCP是面向字节流的,TCP序号也是按照字节来编号的。(这点非常之妙;后面有机制会用到)
比如:一条数据是1000字节;第一个字节的序号是1;第二个字节的序号是2;TCP的报头之记录当前的第一个字节的序号;报头写的是1。(一次连接的编号是按字节数连续;重新建立连接的就是重新编号计算)
接下来第二条数据;从1001-2000;报头写的是1001。TCP知道头的一个字节序号;再根据TCP报文长度;就可以很容易知道每个字节的序号。
A像B发1000数据;应答报文的确认序号填写的是1001;就是在刚才的1000+1;表示含义:
1:小于1001的数据都已经确认收到了
2:A接下来应该从1001这个序号开始继续发送(B像A索要1001的数据)
不直接写作1;而写1001;之所以这样的设定;结合后面机制理解容易。
在这里插入图片描述

2:超时重传

刚才的确认应答我们只讨论顺利传输的情况;如果传输出现问题呢?
传输出问题(丢包):
1:发的数据丢了
2:返回的ack丢了
虽然有两种情况;但是发送方只能看到的结果是没收到ack;没法区分是哪种情况。
重传机制:丢包的时候就重新再发一次相同的数据。丢包是非常小概率;如果重新发一次还是能成功传输。
TCP给一个时间阈值;发送方发一个数据后;就开始等待ack计时;如果在这个时间阈值上ack还没回来;不管ack是在路上还是包丢了;都视为丢包;重新传过。
超时重传那会不会出现一个消息传两次的情况呢?这个问题可不容小觑;比如是支付请求;买一个东西扣两次钱。
处理方法:
TCP会存在一个接收缓冲区(接收方操作系统内核的一段内存;其实发送方也有一个发送缓冲区);比如A给B发消息过程
B的网卡读到A的数据;把这个数据放到接收缓冲区;后续你要getinputStream、read等操作都是从接收缓冲区读取数据(接收缓冲区;想象成阻塞队列;根据数据的序号;如果数据重复就丢弃掉后来的数据。因为序号是唯一的。像一个优先级队列;会对接收到的数据进行重新排序;使收到的顺序和发送的顺序是一样的)
在这里插入图片描述
如果第二次重传还是丢包呢?
会继续重传;当重传到一定次数时就不会继续重传;因为丢包是小概率;如果重传几次还丢包那就极有可能是网络出现故障。然后TCP就重置连接;重置还是失败就彻底断开连接。
重传的超时间隔是多少合适:
一般重传次数越大;超时间隔越大;(1)可以避免是因为ack回来慢被你认为丢包的情况;(2)降低重传的频率;重传次数越多;说明成功概率越小;如果是几乎0%的成功率;那传那么快有什么意义呢;只会白白浪费系统的资源。

可靠传输是TCP最核心的地方;而可靠传输是通过 确认应答+超时重传体现 (一个描述顺利传输情况;一个描述传输出问题情况)

3:连接管理

连接是什么?连接的建立呢?
TCP的建立连接:比如A给B发消息;需要A要一个空间储存B的ip和端口号;B也要一个空间储存A的ip和端口号。当这两部分信息被维护好后;连接就建立了。这个储存这些连接信息(数据结构)的空间也称为连接。
比如:我被坤哥球技深深吸引;想和他一起练习;有一天我特意潜伏在坤哥练习的路上。我们互加了微信;并在微信留下各自的地址。
连接就建立;我可以通过微信里的地址找到坤哥。然后坤哥发现我练习不到30个月;很生气把我微信删了我就没法通过微信的地址找到坤哥;连接就断开了。(这里有个问题;连接是一方断开就行;还是得双方都断开才行。具体得看四次挥手过程)

断开连接呢?
A和B把自己储存的连接信息(数据结构)删了;这时候就是连接断开。
连接管理的管理又是什么?
管理:描述连接是如何创建,如何断开的。建立连接的过程(三次握手);断开连接的过程(四次挥手)

三次握手

建立连接过程(三次握手):举个例子
在这里插入图片描述
互相寻求认同;客户端会发送报文寻求建立连接;服务器接收到要回复并且还有与客户端建立连接请求,最后客户端再给你发消息就完成连接建立。其中服务器的两次是可以合成一次通信的。(各自向对方发一个建立连接的请求;然后再向对方回应一个ack)
应答报文(ack)和建立连接的报文合并为一个;所以我们就称之为三次握手。因为这样子只需要封装分用一次。

这里的建立连接和确认应答机制区别:
针对不同的场景;这里的连接管理的建立连接的过程 在确认应答的基础上专门针对我们建立连接这个环节来进行的特殊操作。增加这个很多功能;所以得把这个建立连接的交互过程和后面连接建立和的确认应答过程区分开。

那么两次握手行不行?
在这里插入图片描述
我这边已经知道坤哥能带我打球;但是坤哥没收到我的反馈;坤哥:这小子是不是外面有人了。他(服务器)还不知道我(客户端)是否答应他(服务器)的建立连接。
比如打游戏连麦:连麦;A:能听到吗 B:能听到;你能听到吗 A:如果两次握手;那我不回复;B怎么知道对方是否接受我的连接建立。虽然是A发起的;但是因为其它故障问题;导致A连不上B的请求,所以这就需要多一次来验证。

三次握手意义:
让通信双方建立对对方的认同;感知对方的存在;建立关系
验证通信双方的各自发送能力和接收能力是否正常;这里两次握手就不行。
握手过程还能协商一些重要参数;比如从哪个编号开始;还有通信过程有些数据需要双方互相同步;那还没交互怎么同步;正好有三次握手。
三次握手一定程度保证TCP传输的可靠性(虽然相较于确认应答;超时重传比较微小;但是贡献还是有的);
在这里插入图片描述
连接:连接的建立;断开;维护;三次握手只是建立的这个环节。accept方法是已经握完;把现成的连接拿到应用程序。

真正意义上的三次握手:
在这里插入图片描述

SYN:客户端主动给服务器发起的建立连接请求(用于TCP建立连接时进行握手协议,表示望建立连接,并且交换双方的序列号)SYN(synchronze)同步报文段。
两边的是TCP状态:TCP状态很复杂;我们先认识一下建立连接时的两个状态
1:LISTEN;服务器的状态;表示服务器已经准备就绪;随时可以有客户端来建立连接
2:ESTABLISHED;客户端和服务器都有的状态;连接建立完成状态;接下来就可以正常通信

在这里插入图片描述

在给他人讲解注意画图更好理解;线上电脑画;线下自带纸笔。
在这里插入图片描述

四次挥手

断开连接:四次挥手;和握手是一个意思;都是客户端服务器数据的交互

在这里插入图片描述
这里的中间两次通常不能合并(只有在特殊情况下才能合并;数据发送时机相同才能合并);三次握手是同一时机;因为是系统内核完成;一旦握了就无法反悔;程序没法干预

在这里插入图片描述
FIN是什么?
控制标志,用于表示TCP连接的结束或关闭。
当一个端口要关闭与另一个端口之间的TCP连接时,它会发送一个带有FIN标志的TCP数据包给对方。这表示它不再发送数据,并且要开始释放连接资源。接收到带有FIN标志的数据包的一方会发送一个ACK(确认)回复,然后也发送一个带有FIN标志的数据包给对方,表示它同意关闭连接。

这里是程序可以控制的;不知道你是不是发送ack;然后就跑去执行别的东西;或者在休眠;所以时机不是同步的。相隔的时间;时间差取决你代码怎么写的。(客户端进程退出也是触发FIN)
我们之前的网络编程TCP编程:在这个代码;循环一结束就close发起FIN;这时候ACK和FIN的时机很短;可能就合并了;
在这里插入图片描述
但是如果中间相隔时间比较长;就无法合并
在这里插入图片描述

在这里插入图片描述

FIN为1发送结束报文。
在这里插入图片描述
在这里插入图片描述
你就得检查你的代码;是不是这里被阻塞了;没有执行到close
TCP状态:
1:CLOSE_WAIT;出现在被动发起断开连接的一方;意思是等待调用close方法关闭socket;如果应用层的程序还没执行close方法就会一直处于这个状态
2:TIME_WAIT;出现在主动发起断开连接的一方;进入这个状态时;相当于四次挥手都挥完了。既然都挥完了为什么就不是CLOSED状态呢?
因为这里服务器发送FIN数据报;我们还得给它返回一个ACK;需要等待一会;等ACK发送过去(正常情况下服务器收到ACK后就直接关闭;释放资源。客户端并不知道B是否收到ACK;会等2msl;这个时间过去;服务器没有重新再发FIN报文索要ACK就关闭)
如果ACK丢包;服务器就收不到ACK(可能ACK丢了;也可能FIN报丢了;服务器并不知道);触发超时重传;会重新发FIN报索要ACK;客户端收到后就重新发一份ACK。

如果第一次ack丢了;重传的FIN包也丢了;时间超过2msl;那么客户端就认为你没有再给我发FIN报索要ACK;然后就彻底断开连接。所以一旦进入这个状态;连接必然会断开的;不可逆。

那服务器怎么断开连接呢?
超过这个时间双方强制断开;

为什么设定时间是2msl?
这个等待时间是设定2msl;msl互联网上两个节点传输消耗的最大时间。ACK丢一次是一次msl时间;重新发回去也是msl时间。所以就设定2msl。去向ACK消息最大存活时间(MSL) + 来向FIN消息的最大存活时间(MSL)。

机制4:滑动窗口

TCP通过很多机制来让传输变的可靠;在极限的快与准当中必须得要有所牺牲;在准的前提下尽可能提高效率;方可达到又快又准。比如:七步之外;枪快。七步之内;枪又准又快。所以我们需要增加一些条件;使得枪在七步外准且快;比如瞄准镜。

滑动窗口机制:本质上为了降低确认应答等待ack的时间;就比如IO操作时;大部分时间都在等;少部分时间在数据传输。
不再是发一条等一个ack再发下一条;而是一组一组的发;

在这里插入图片描述
上面窗口大小为4000;发送一组再批量等。约定窗口大小;发多少后等待。一般来说先发的先到;我们可以继续往后发。像窗口一样往后滑动。比如:等待ack1001到5000数据;收到2001的ack就说明1001-2000的数据已经发到了;就往后滑;等待ack的范围变成2001-6000。
ack后发先至:也可能是3001的ack先到;2001ack在路上或者丢了;那不要紧;因为3001这个ack涵盖2001的ack信息;就能证明前面的数据是发送成功的;滑动就可以一下滑两个;直接从3001后面开始。(实际上ack也不会老老实实全部都发;可能隔几条发一下)

为什么知道3001就能证明前面的数据发送成功:
(不然你以为这个3001数据是怎么来的;说明这里数据序号是从2001开始;是通过2001序号后加个1000的数据量来的;如果2001没发送成功;这里就不可能是3001;而是一直在等2001的ack)

虽然说第一段数据没有及时往下滑;而是等第二段数据通知后才一起往下滑;对效率的影响是微乎其微;小概率‘中间少等两个ack对效率影响也是很小的。
在这里插入图片描述

丢包问题:

针对这个丢包问题:可能ack丢了;也可能包丢了。如果ack丢了咱啥也不用做;不可能所有ack都丢了;反正后面的ack就能证明前面的是已经成功发过去。
丢包:比如A给B先发送1001-6000数据;1001-2000丢包;2001-3000成功发送过去后;B返回的ack就不再是3001;而是返回ack的确认序号1001(因为发送的数据是有编号的);因为这个包丢了;所以B在向A索要1001开头的数据。接下来几个数据返回的确认序号都是1001。其它三条ack都在索要1001开头数据;A就会进行重传。重传后成功后;B后续返回ack序号就是7001。中间还有其它丢了;ack序号就会在那里开始。

快速重传

这种重传方式叫快速重传:只重传丢失的数据;可以看做是超时重传在滑动窗口下的变形;数据是密集就按照这种方式重传;如果数据稀疏就不按照滑动窗口方式;而是超时重传处理丢包;因为数据稀疏可能隔很久才发下一条;等一段时间发现没有ack就重传。
虽然这个发送过程到B数据可能乱了;但是TCP有一个接收缓冲区;会对缓冲区这些数据重新排序。确保跟发的顺序一样

机制5 流量控制

流量控制:干预发送窗口大小的机制;窗口越大效率越高;但是也不能无限大。
窗口太大可能会大量消耗系统资源;发送速度如果太快;接收方处理不过来;也是白发。如果超过接收方处理能力还是会丢包;丢包又得重传。
在这里插入图片描述
窗口大小:
直接看接收方缓冲区剩余空间大小;如果剩余的空间大;说明接收方处理能力强;可以发快点。会把剩余的缓冲空间的信息通过ack报文返回;然后就会通过这个值决定接下来发送的速率是多少。这里16位窗口大小;得是ack这里值为1才有效;报文是ack才有效。相当于告诉你该用多大窗口;不一定就一定按这个窗口发送;会参考一下。
16位;但是最大不止是64kb;TCP在选项部分引入窗口扩展因子;比如扩展因子写个2;意思是64kb左移两位变256kb(移动一位就扩大两倍)。接收方缓冲区剩余空间动态变化;每次返回ack带的窗口大小都是在变化;发送方也是在动态调整。
如果窗口大小到0呢?
窗口大小到0就告诉你别发了;要等等。发送方也不是完全不干活了;但是他会发一个窗口探测报文;不带任何业务数据;只是为了触发ack查询窗口大小。
在这里插入图片描述

机制6 拥塞控制

流量控制和拥塞控制共同决定发送方的窗口大小是多少。
拥塞控制:描述传输过程中间节点的处理能力;流量控制只考虑发送的速率和接收方的处理能力;但是网络传输中间还是要经过很多节点;所以刚才的16位窗口大小;也只是参考。

通过测试方法找到一个合适的窗口大小:
在这里插入图片描述
在不丢包的前提下;先指数增长;到阈值后就线性增长。一旦丢包;说明速率接近极限;一下子就缩成很小的值;重复刚才的过程。这次最后结果到刚才网络拥塞的值除2换线性增长。拥塞窗口也是动态变化的;慢慢的逐渐达到一个平衡的过程。
拥塞窗口和流量控制的窗口两个共同决定发送方的实际窗口;谁小就使用谁的。

机制7 延时应答

延时:收到数据后不是立即返回ack;而是稍微等一会再返回;利用这个等待时间接收方就能把数据消化更多;剩余空间更大。延时应答也是为了提示效率;在滑动窗口上做的事情。(我等一会;因为现在我都处理不过来;再发过去;对方又给我发一堆数据;比如我就前面的ack不发;然后发后面的)
在这里插入图片描述

机制8捎带应答

延时应答的基础上引入的捎带应答。服务器和客户端典型的模型是一问一答。
这里是正常的交互;而三次握手;四次挥手是建立和断开连接过程;特殊情况。
在这里插入图片描述
坤哥的自动回复和他发消息的时机是不同的;但是因为TCP的延时应答;可以让ack等多一会;和坤哥回复的消息一起发过去;这样子就一次发送就能完成。一定概率合并;看程序怎么写的(服务器立即响应;还是需要完成一下其它工作再响应呢);如果时机接近就能融合。和四次挥手比较相似;捎带应答是说明能合并;延时应答是为了提高合并的概率。

面向字节流-粘包问题

面向字节流;可以一次读1-n个字节;引入一个麻烦事情;粘包问题;接收缓冲区把多个数据放一起。读的时候就麻烦了;inputStream的read方法应该读到哪才是应该完整的数据报呢?
解决方案:
应用层约定好协议;明确数据报之间的边界;比如回车换行;空格;空白符。约定好分割符。或者约定好每一个数据报的长度。

异常情况(进程崩溃、主机关机–主机断电、网络断开)

1:进程崩溃;进程没了;PCB对应文件描述符表释放;相当于socket.close()。内核会继续完成四次挥手;还是一个正常的断开流程(不一定能挥完;难免出现丢包问题;已经释放就无法继续重传)
2:主机关机;正常关机;主机先杀进程;然后正式关机;杀进程也是向上面socket.close();进行四次挥手。

3:主机断电
4:网络断开
3、4是一个道理;来不及挥手;发送方还在发数据;等你的ack;等的到吗?发送方等不到超时继续重传;重传几次后就重置连接;重置连接失败后就单方面放弃连接。
如果是发送方断电:接收方发现没数据;先等一下(此时接收方并不知道你是在准备发还是已经断电了);接收方会周期性给发送方发一个消息;确认对方是否还工作正常。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

瞭望~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值