一.滑动窗口
滑动窗口:可以提高传输效率,准确的来说是让tcp在可靠传输的前提下,效率不要太拉胯。使用滑动窗口不能使tcp变的比UDP块,但能减少差距。
前面谈过tcp的传输数据的时,会把数据进行编号,每次传固定的长度。比如主机A给主机B发信息,信息经过应用层后到传输层,tcp会把应用层发来的信息通过每个字节进行编号,假设编号为1到3000,tcp会批量传输编号内容。设主机A第一次传输编号为1到1000的内容。主机B收到给A返回确认应答后,主机A才能接着发1001到2000的数据。
这样传输能够保证可靠性,但大量的时间都消耗在等ack上了。使用滑动窗口就是为了缩短等待时间。
一次性发出一组数据,发送一组数据的过程中不需要等待Ack,就直接往前发。此时就相当于使用一份等待时间等四个ACK。把一次发多少个数据,不用等ACK的大小称为滑动窗口。窗口越大此时批量发送的数据越多,效率就越高,但是窗口不能无限大,如果无限大,相当于完全不必等,此时就和不可靠传输一样。
主机A假设一次性传1-2000,2001-3000,3001-4000,4001-5000,这样的数据就需要4个ack,虽然一次性发了4条数据但是等主机B的4个ack都返回后在进行第二轮发送显然效率有点慢,可以等第一条数据的ACK收到后直接进行第二轮发送,发送50001-6000的数据,这样还是等4条ACK,窗口大小还是一样大,只是往后平移了一个格子。这样可以缩短时间,比之前能提升一定的效率。
如果按照滑动窗口传输数据丢包了咋办?
对于Tcp提高效率,必然不应该影响可靠性。2种情况数据丢了和Ack丢了。
1.ack丢了:
ack丢了,不用做任何处理,也是正确的。假设2001到3000数据的Ack丢了,但是4001到5000的Ack在说明4000之前的数据都发送成功了,此时并不需要重传。
2.数据丢了
假设1001到2000的数据丢了,3001到4000的数据到达了B,B返回的确认应答任然是1001,会一直向A索要1001到2000的数据,当A连续收到几次B的索要,A就明白1001到2000的数据丢失了,A就会重传1001到2000的数据。
如果接收缓冲区1001到2000少了。返回的Ack会始终索要这个数据,一旦1001这个数据报补上了,此时1001到2000后面的数据报都不必要重传了,接下来看后面的数据哪里有缺失,如果有补上,没有直接索要缓冲器的最后一个数据的下一个即可。
滑动窗口并不是使用tcp一定会涉及,通信双方大规模传输数据的时候会使用滑动窗口,如果数据较少仍然按照超时重传。
二.流量控制
滑动窗口,窗口越大,传输效率越高,但是窗口也不能无限大,如果窗口太大,就可能使双方处理不过来了,或者是中间的传输链路层处理不过来了。这样就会丢包,得重传,反而影响了效率。流量控制就是给滑动窗口刹车。
通过流量控制限制发送方发射窗口的速度。数据发送到缓存区后,此时就会把缓存区剩余空间大小,通过ack报文反馈给发送方,作为下一次发送数据,窗口大小的依据。
假设内存缓存区的空间大小为4000,A第一轮发送的数据占用4000大小的空间,缓冲区空间大小已满,这个时候A就不能继续发数据了,等B去消耗数据,A在等待的同时会时不时给B发送窗口探测包(不会携带具体数据),只是为了触发ACK(查询当前接收缓冲区的情况)。一旦发现内存空间释放了,就可以继续发送了。接收方可以根据窗口的大小就可以反向限制发送方传输速度了。
三.拥塞控制
传输数据的时候要经过很多线路,路由器,交换机。每个路由器交换机处理数据的能力不一样,如果中间某个节点处理数据的能力特别差,那么主机A发送数据的能力不能超过这里的阀值。总的传输效率是一个木桶效应,取决于最短板。
虽然中间的设备一般由运营商提供的企业级路由器/交换机,整体的转发的能力特别强,但如果量很大的话也会堵车。具体怎么衡量中间设备的转发能力呢?把中间的设备看做一个整体,采用实验的方式,动态调整,产生一个合适的大小。
1.使用一个较小的窗口,如果传输正常就增大窗口。
2.使用一个较小的窗口,如果丢包就减小窗口。
而拥塞窗口就是在拥塞机制下,采用的窗口大小。
tcp中拥塞控制具体是这样展开的:
1.慢启动,刚开始通信的时候,会使用一个较小的窗口来试水。
2.指数增长:在传输通畅的过程中,拥塞窗口会指数增长。
3.线性增长:当拥塞窗口指数增长到设定的阀值时,会线性增长。
4.拥塞窗口回归最小窗口:当窗口大小增长过程中,如果出现丢包,认为当前网络拥堵了。此时就会把窗口调整成最小的小窗口,继续回到指数增长加线性增长的过程中,另外会根据当前丢包的窗口大小,调整阀值。
拥塞控制和流量控制共同限制了滑动窗口的大小,可以使滑动窗口在可靠性的机制下,提高传输效率。
四.延迟应答
是否有办法在滑动窗口的基础上再次提高效率?需要在返回ACK的时候,延迟一点时间,利用这个时间,就可以给应用程序腾出来更多的消费数据的时间。接收缓存区剩余空间就会更大了。
如果数据传过来,此时立刻返回ACK此时窗口的大小就是3kb,稍等500ms,此时在返回ack,就有可能在这500ms里面又消耗了2kb数据,此时返回的窗口大小就是5kb了。
五.捎带应答
稍带应答在延迟应答的基础上,让ack和响应一起返回,提高了效率。
数据从两个合并一个,效率会有明显的提升。主要还是因为这里每次传输数据都需要封装分用。
能合并的原因,一方面是时机是可以同时的,一方面ACK本身不需要带载荷,和正常的数据不冲突,完全可以让一个数据报,既能够携带载荷数据,又能带有ack信息。
六.面向字节流
在面向字节流的情况下会产生粘包问题。粘包问题是数据发送过来,tcp会把数据进行编号,根据编号每次发送一部分数据。那么数据报发过来,但是接收的时候怎么知道从哪里到哪里是一个完整的应用数据报,这就是粘包问题。
发送是2个包,读可能读了半个或者一个半,这个时候都会产生问题。
站在发送方的角度预期,aaa是一个应用层数据报,bbb是一个应用层数据报,ccc是一个应用层数据报。此处正确的做法是合理的设计应用层协议,这件事情在传输层很难解决,需要在应用层解决这个问题。
1.应用层协议中,引入分割符,区分包之间的边界。
2,应用层协议中,引入包长度,也能区分边界。
1.使用\n约定包之间的分隔符
2.使用包的长度区分
粘包问题不仅仅是tcp才有的,只要是面向字节流(文件)也有同样的问题,解决问题都是一样的,要么使用分割符号,要么使用长度。