TCP可靠传输机制
滑动窗口
上述的机制都是针对TCP
的可靠的传输设计的!
而在可靠传输的基础上还要保证传输效率!
滑动窗口机制就是提高TCP
网络协议的传输效率!
我们可以看到,如果TCP
每次传输一次数据就要等待一个ACK
确认序号后再进行传输数据,显然这样每次等待ACK
这就使得TCP
的传输效率很慢,而滑动窗口就解决了这个问题!
我们可以一次发送多组数据,每组数据都会有一个ACK
我们同一发送完一组数据后,再一次等待ACK
保证传输的可靠性同时又保证了传输效率!
- 这里的一组数据的数据条数就是窗口大小,在窗口大小的范围内,我们无效等待
ACK
可以继续发送数据! - 滑动,就是我们接收到
ACK
后,我们的窗口位置就可以往后滑动,又可以进行数据发送!
这张图就很好的诠释了滑动窗口!
这里一组数据有4条数据,就是窗口大小为4!
当我们已经接收到了ACK
2001时,我们就知道1001-200数据已经发送成功,窗口向下滑动!
一起发这么多ACK
,如果出现丢包问题,该如何解决呢?
-
ACK包丢失,数据到达!
这种情况,我们并不需要处理,就如上图,虽然ACK1001丢失了,但是后面的2001接收到了,我们知道,接收到了ACK2001说明前2000个字节数据传输成功,也就是ACK2001涵盖了ACK1001的功能!后面的4001丢失也是如此,我们已经接收到了5001,就保证了1-4000数据已经发送成功!
-
数据丢失
数据丢失,就需要进行处理,可以看到当1001-2000
数据丢失后,虽然这一组数据的发送并没有结束,但是每次的ACK1001
确认序号都是一样的,服务器向客户端索要1001-2000
数据,在进行这一组数据的发送后,客户端会将数据重发!
我们知道主机B会将数据保存到接收缓冲区,在没有接收到1001-2000
的数据,接收缓冲区会留有一块空间!
直到接收到1001-2000
的数据将其补上!
这种机制叫做高数重发机制(也叫快重传)
流量控制
流量控制是在滑动窗口机制上对其补充!保证了传输的可靠性!
我们了解到在主机A和主机B进行通信时,主机A的数据先保存到主机B操作系统中的接收缓冲区当中!
我们又说过,接收缓冲区是一个阻塞队列,那么当主机A的传输数据过快时,那么数据就会在主机B中的接收缓冲区阻塞,如果主机A继续发送数据就会导致丢包问题!
因此TCP根据接收方的处理能力,来决定发送速度,这个机制就叫做流量控制!
TCP如何得知接收方的处理能力呢?
- 接收方通过将接收缓冲区剩余空间大小放在
TCP
报文中的16位窗口大小中,然后通过ACK报文告知发送方! - 窗口大小越大说明,接收方的处理能力越强!
- 当接收缓冲区将要满时,发送方会减小发送速率,避免产生丢包!
- 如果接收缓冲区满了,那接收方就会回将0保存在16位窗口中!发送方收到ACK后就会停止数据传输,会过会时间定期发送一个窗口探测报文,接收方会将窗口大小返回给发送方!
我们知道16位窗口大小只能保存最大数据为65535字节,那么一个TCP数据报超过65535字节呢?
我们TCP报文中还有一个40字节的选项,这里面包含了一个窗口扩大因子M,实际的窗口大小可以是16位窗口大小+M左移因子!
拥塞控制
这也是滑动窗口的延伸,限制滑动窗口的发送速率保证可靠性!
拥塞控制是衡量发送方到接收方,这整个线路之间的拥堵状况(处理能力)这里和流量控制一样限制了发送方的传输速率!
我们知道两个设备进行通信,中间链路情况十分复杂,中间有很多设备,而每个设备的信息处理能力又不一样!如果中间一个设备处理的很慢,那其他设备处理的再快也无济于事!
这就导致,整个链路的传输速率也下降,这也促使发送方降低发速率!
发送方如何得知中间链路的阻塞状态呢?
这里无法直接得出,我们需要通过实验得出一个结论,找到这个最适合的发送能力,既要保证传输速率快,又要避免丢包!
- 发送方一开始取的拥塞窗口大小非常小,取纵轴的1个单位(1个单位的大小是1个字节,10个字节,具体要看操作系统代码如何实现)
- 一开始发送方通过指数增长的方式,增加传输速率,到达了一个合适的值后,就降低增长速率!
- 到达阈值后就是指数增长就会变成线性增长,使速率无限接近最大速率,直到产生丢包
- 丢包后,说明网络拥塞,自接将速率减少到最开始的初始值,避免丢包过多,又反复进行上述过程,当第二次指数增长时,会将阈值减小到当前出现丢包窗口的一半(一开始到达
24
就产生了丢包,那第二次就会将阈值减少到12
),然后进行线性增长,直到找到一个最合适的值!
这个过程可能有些许复杂,可以联系俩个人谈恋爱!
一开始在一起时,热恋期好感度指数增长,到了后面,新鲜感没了,没有增长的这么快了,最后吵架闹分手,就好感度一重新开始,所谓小别胜新欢,然后又热恋,显然这次热恋期没第一次长,然后种种最后爱情的镜头还是财米油盐!
这里的拥塞窗口和刚刚的流量控制都是对发送方发送速率的约束,那么最后发送方发送的速率是取决于那个呢?
发送速率 = Min(拥塞窗口,流量控制);
延时应答
演示应答是流量控制的的延伸
流量控制是告诉发送方不要发送的太快!
延时应答是在这个基础上,尽可能然窗口更大一些!
刚刚的流量控制,当接收方的接收缓冲区满后,发送方就会停止发送数据,而是定期发送窗口探测报文,为了得知当前接收方接收缓冲区的大小,然后接收方就会发送返回一个窗口大小的报文!
而这里的延时应答就是将这个窗口大小的报文延时传送给发送方!
这样延时处理后,给接收方些许时间处理数据,使得窗口大小变大,然后下次发送方就可以提高发送速率!
捎带应答
这里又是延时应答的延伸!
因为延时应答的存在导致接收方接收到数据后ACK
可能不是及时传输,那么当ACK
延时后,当再次发送时,发现和另一条发送数据的发放时间一样,那么就可以将ACK
和另一条数据一起封装分用,进行打包发送,提高发送效率!
就是将ACK
和数据一起打包传输返回给主机A!
客户端和服务器之间的通信方式有多种!
- 一问一答:客户端一个请求返回一个响应(网页)
- 一问多答:下载文件
- 多问一答:上传文件
- 多问多答 :直播
这里的捎带应答策略针对的是一问一答方式
这里捎带应答ACK
和数据报丢了咋整,和正常的丢包程序一样处理!
面向字节流
TCP是面向字节流读取数据的,也就导致了一个粘报问题!
所有的面向字节流都会存在粘包问题!
粘包问题:
当主机A发送3条数据给主机B时,3条数据就来到了主机B的接收缓冲区,然后应用程序通过socket中的read方法读取数据,面向字节流读取,这时应用程序也无法区分数据包,就出现了粘包问题!
如何解决呢?
显然我们的应用层数据拿到的数据时进行了分用的,也就是说并没有TCP协议中的字节确认序号,所以这里要通过对应用层协议的改进才能解决粘包问题!
在设计应用层协议时就要对数据通过标记位或者分隔符进行分割!
在应用层协议设计好就处理了粘包问题!
如果我们是基于某些库和框架来完成的网络通信,一般来说粘包问题已经被库和框架解决了,如果你是自己实现的库和框架使用TCP协议那就需要考虑粘包问题!
TCP的异常处理
- 进程终止
当我们强制杀死一个进程时,这时的TCP连接是咋样呢?
TCP
连接是通过Socket
来建立的,Socket
本质是进程打开的一个文件,而文件就存在于进程的PCB
中的文件描述符表,每次打开一个文件(包括Socket
)就会在文件描述符表中添加一项!
每次关闭一个文件就在文件描述符表中删除该项!
如果直接杀死进程,PCB
也就没了,文件描述符表自然没了,相当于手动调用了socket.close
效果一样! - 机器关机
关机机器会先通过操作系统将主机中的所有进程强制结结束也就和上述的进程终止一样,然后再关机 - 机器掉电/网线断开
机器掉就是电台式机拔掉了电源
操作系统毫无防备,没有对该进程处理后事!
主机B接收方挂了
主机A并不知道该主机已经断电!
一直在等待ACK
然后进行超时重传,重传失败几次后就会重新建立连接,最后发现无济于事就断开了连接!
主机A发送方挂了,主机B并不知道是什么原因是A休息了,还是A挂了!
主机B就会时不时发送一个小的报文(不带数据的,只为触发ACK)心跳报探测报文,当A不再放回ACK就认为A出现了问题,就断开连接!
TCP和UDP对比
![](https://res.hc-cdn.com/ecology/9.3.130/v2_resources\images\global\blog-dialog.png)
华为开发者空间发布
让每位开发者拥有一台云主机
- 点赞
- 收藏
- 关注作者
评论(0)