1.传输层协议(TCP传输的机制补充)
1.1.滑动窗口
滑动窗口存在的意义就是在保证可靠性的前提下,尽量提高传输效率.
由于TCP是得保证可靠传输的,所以每一次数据发送时都需要等待对方的ACK.大部分时间都用在等ACK上,而确认应答是可靠传输的主要机制又不能不等.所以有了新的机制就是滑动窗口.
- 滑动窗口就是首次发送多组数据,发送过程不进行等待.
- 窗口大小:一次批量发送N份数据.N 就是窗口大小
- 发送完成后统一等待多组数据的ACK(将多份ACK的等待时间压缩成一份等待时间)
- 等待到第一份数据的ACK后,滑动窗口开始向后移动,发送N+1的数据(ACK等待范围变为 2–N+1),以此类推.
1.1.1.滑动窗口的丢包问题
- ACK丢包:
- 要了解ACK丢包后的机制就要先了解滑动窗口中确认序号的含义
- 确认序号中的内容表示当前序号之前的数据全都确认收到了.比如收到了N的ACK 说明 [0,N) 的数据都已经收到了,就是N之前的数据已经收到了)
- 由于确认序号的特殊原理,所以当ACK丢包时,只要后面数据的ACK能到达.前面数据的ACK也就无关轻重了
- 要了解ACK丢包后的机制就要先了解滑动窗口中确认序号的含义
- 数据丢包:当某一段报文段丢失之后,发送端会一直收到相同的ACK(比如 N丢包了,当收到N往后的数据,就会返回一个N的ACK),就像是在提醒发送端 “我想要的是 N” 一样;
- 如果发送端主机连续多次(一般为三次)收到了相同的应答,就会将对应的数据重新发送;
- 在接受到 N的数据 之前,其他接收到的数据会放到了接收端操作系统内核的接收缓冲区中组织.
- 接收端收到了 N的数据 之后,会返回新的ACK.返回的新的ACK就是已经接收到连续的数据的最末端ACK.
- (比如:已经 97的数据丢失 ,接收到 98,99,100 的时候会不停返回 97 .然后发送端就会重新发送97的数据. 接收到97的数据之后,就会发送 101的ACK ).
1.2.流量控制
流量控制是滑动窗口的延伸,目的是为了保证可靠性.
滑动窗口中,窗口越大,传输速率越高.但是如果发送方一味的发送,不考虑接收方的话.会导致接收方处理不过来,接收方就会把很多包丢掉,之后发送方又要重新重传(效率不增反减).
- 流量控制:TCP根据接收端的处理能力,来决定发送端的发送速度.使发送和接收达到一种动态平衡.
- 接收缓冲区剩余空间比较大时,就认为接收端的处理能力比较强.就可以让A发快点
- 接收缓冲区剩余空间比较小时,就认为接收端的处理能力比较弱.就可以让A发慢点
- 窗口大小:接收方通过ACK报文中的窗口大小来告知发送方接收缓冲区的剩余空间.发送方根据这个数据灵活调整.
- 窗口大小虽然只有16位,但是实际上的窗口大小可以更大.
- 选项中有一项 窗口扩大因子M ,表示实际窗口大小是窗口字段的值左移M位.
- 当窗口大小为0时,就意味着发送方不再发送实际数据.
- 但是会时不时发送探测报文.为了触发ACK,从而得知当前的窗口大小.
- 不止发送方会询问,同时接收方也会在窗口更新的时候,向发送方发送一个窗口更新通知.
- 窗口大小虽然只有16位,但是实际上的窗口大小可以更大.
1.3.拥塞控制
拥塞控制也是滑动窗口的延伸,目的是限制滑动窗口发送的速率.
发送方的发送速度不止取决于接收方的处理能力,也取决于中间链路的处理能力.而最终窗口大小由这两个共同决定(取其中的较小值).
- 流量控制衡量的是接收方的处理能力, 拥塞控制衡量的是整条链路之间的处理能力.(整条线路的拥堵情况)
- 由于很难对中间链路各个节点的处理能力衡量, 所以采用一种 “实验” 的方式,逐渐调整发送速度,找到一个比较合适的值(范围).
- 发送方从一个比较小的窗口开始发送数据.如果数据很流畅的就到达了,就逐渐加大窗口大小.
- 加大到一定程度之后,出现了丢包(丢包意味着通信链路出现拥堵了),再适当调整窗口大小.
- 反复实验 ,逐渐找到一个合适的范围.
- 拥塞窗口就在这个范围中不断变化,达到"动态平衡".
1.4.延迟应答
延时应答的目的是提升传输效率.
如果接收数据的主机立刻返回ACK应答, 这时候返回的窗口可能比较小.
- 采取策略:不是立即回答,而是稍微晚一些回答.
- 在这个等待的时间里,就可以处理一些数据.从而应答中返回更大的窗口.
1.5.捎带应答
捎带应答是延时应答的延伸.
由于有了延时应答, 所以可以将ACK和数据打包在一起发送. 所以捎带应答可以说是给ACK搭顺风车.
2.粘包问题
只要是面向字节流的协议就会有粘包问题.
- 首先要明确,粘包问题中的 “包” 是指的 应用层的数据包.
- 因为在TCP的协议头中, 没有如同UDP一样的 “报文长度” 这样的字段, 但是有一个序号这样的字段.
- 站在传输层的角度, TCP是一个一个报文过来的. 就可以按照序号排好序放在缓冲区中.
- 但是站在应用层的角度, 看到的就只是一串连续的字节数据.
- 那么应用程序看到了这么一连串的字节数据, 就不知道数据是从哪个部分开始到哪个部分结束.
- 这样就产生了粘包问题
粘包问题的解决方案: 就是在应用层协议里面添加包的边界.或者显示包的长度.
- 如果基于一些库和框架来完成网络通信,一般粘包问题已经被处理了.
- 但是如果是自己实现,就需要注意粘包问题.
3.TCP的异常处理
- 进程终止
- 进程终止会释放文件描述符, 仍然可以发送FIN. 和正常关闭没有什么区别.
- 机器重启
- 机器重启和进程终止的情况相同.
- 机器掉电/网线断开
- 如果是接收方断开.就会不再发送ACK,接收方进入超时重传逻辑,多次重传后重新建立连接,依然失败,主动放弃连接.
- 如果发送方断开.接收方只能被动的等,但接收方也不会傻傻的等,会周期性的触发探测报文(心跳包:为了触发ACK).通过探测报文发现A不再返回ACK了,就放弃连接.
4.TCP vs UDP
- 对于可靠性有一定要求一般使用TCP(日常开发中的大多数情况都是基于TCP)
- 对于可靠性要求不高,对于效率要求更高的一般使用UDP(机房内部的主机之间的通信,分布式系统中)