美文网首页
TCP和UDP的区别

TCP和UDP的区别

作者: ChaLLengerZeng | 来源:发表于2018-11-10 19:36 被阅读78次

    TCP和UDP的区别

    首先TCP是面向连接的,UDP是无需连接的,TCP有着三握四挥,并且三次握手和四次挥手是对TCP建立的连接有着重要意义的两步,并且TCP是对IP无可靠性提供可靠性的源头,UDP继承了IP的特性,不保证不丢失包,不保证按顺序到达

    TCP面向字节流,发送的时候是一个流,没有头尾,IP包不是一个流,而是一个个的IP包,UDP也是如此

    TCP是有拥塞控制的,但是UDP没有

    UDP

    image

    MAC层去掉之后,IP层首部会有一个8位的协议,这里会存放着数据里到底是TCP还是UDP,当然这里是UDP,如果我们知道UDP格式就可以解析出来了

    下一步就通过UDP包中的目标端口号,将这个包交给应用程序处理

    UDP使用场景

    • 需要资源少,网络情况较好,或者对于丢包不敏感的应用
    • 不需要一对一沟通,建立连接,而是可以广播的应用,DHCP就是一种广播形式,基于UDP
    • 需要处理速度快,时延低,可以容忍少数丢包,但是要求即使网络拥塞也不退缩,这也就早就了UDP的简单、处理速度快,不用担心别的事情

    TCP

    image

    源端口和目标端口不可少,包的序号是为了解决乱序问题,为了解决包的先后顺序,还有就是确认序号,发出去的包要有确认,不然无法知道是否收到,若没有收到就要重新发送,直到送达,这就是TCP的不丢包的实质

    对于TCP来说,IP层丢不丢包管不着,但是在TCP层,会努力保证可靠性

    • 顺序问题,稳重不乱
    • 丢包问题,承诺靠谱
    • 连接维护,有始有终
    • 流量控制,把握分寸
    • 拥塞控制,知进知退

    三次握手

    • SYN 发起一个连接
    • ACK 回复
    • RST 重新连接
    • FIN 结束连接
    image

    一开始,客户端和服务端都处于CLOSED状态,先是服务端主动监听某个端口,处于LISTEN状态,然后客户端主动发起连接SYN,之后处于SYN-SENT状态,服务端收到发起的连接,返回SYN,并且ACK客户端的SYN,之后处于SYN-RCVD状态。客户端收到服务端发送的SYN和ACK之后,发送ACK的ACK,之后处于ESTABLISHED状态,因为它一发一收成功了,服务端收到ACK的ACK之后,处于ESTABLISHED,因为它也一发一收了

    • 第一次握手:Client 什么都不能确认;Server 确认了对方发送正常

    • 第二次握手:Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:自己接收正常,对方发送正常

    • 第三次握手:Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:自己发送、接收正常,对方发送接收正常

    所以三次握手就能确认双发收发功能都正常,缺一不可。

    四次挥手

    image

    最后客户端A的TIME-WAIT状态时间要足够长,长到如果B没有收到ACK的话,B会再次发送FIN关闭连接,A会重新发送一个ACK并且时间足够长到这个包到B

    A如果直接跑路的话,它的端口就空出来了,但是B不知道,原来发的包如果在路上,但是这时突然另一个应用开启在了这个端口上,那不就混乱了,所以A也需要等待足够时间,等到B发送的包在网络中挂掉之后再空出端口来

    等待时间设置为2MSL,报文最大的生存时间,协议规定MSL为2分钟,实际应用中常用的是30s,1分钟和2分钟等

    TCP状态机

    image

    窗口

    为了记录所有发送的包和接收的包,TCP也需要发送端和接收端分别都有缓存来保存这些记录,发送端的缓存里是按照包的ID一个个排列,根据处理情况分为下面四个部分

    1. 发送了并且已经确认了的,这些是应该删掉的
    2. 发送了并且尚未确认,需要等待确认的回复之后才可以删掉
    3. 没有发送的,但是已经在等待了的
    4. 没有发送,并且暂时不会发送

    在TCP里,接收端会给发送端报一个窗口的大小,叫做Advertised window,这个窗口大小应该等于上面说的第二部分加上第三部分也就是已经发送了但是没有得到确认的加上还没有发送,并且正在准备发送的,超过这个窗口的,接收端忙不过来,就不能发送了

    发送端需要保持的数据结构

    image
    • LastByteAcked表示第一部分和第二部分的分界线
    • LastByteSent表示第二部分和第三部分的分界线
    • LastByteAcked + 窗口大小 表示第三部分和第四部分的分界线

    接收端需要保持的数据结构

    1. 第一部分:接收并且确认过的
    2. 还没有接收但是马上就能接收的,也是我能够接受的最大工作量
    3. 还没有接收,也没有办法接收的,超过工作量的部分
    image
    • MaxRcvBuffer 最大缓存的量
    • LastByteRead之后是已经接收了的,但是还没有被应用层读取的
    • NextByteExcepted是第一部分和第二部分的分界线

    第二部分的窗口有多大?

    NextByteExpected 和 LastByteRead的差其实是还没有被应用层读取的部分占用调MaxRcvBuffer的量,定义为A,窗口大小其实是MaxRcvBuffer减去A

    其中第二部分里面,由于收到的包可能不是顺序的,会出现空档,只有和第一部分连续的,可以马上进行回复,中间空着的部分需要等待,哪怕后面的已经来了(可以看到接收端的窗口出现了虚线和实线的区别)

    顺序问题与丢包问题

    发送端

    image

    接收端

    image

    发送端看来,1、2、3都已经发送并且确认的;4、5、6、7、8、9都是发送了还没有确认;10、11、12是还没有发出的;13、14、15是接收方没有空间不准备发送的

    接收端看来,1、2、3、4、5都是已经完成ACK的,但是是没有被应用层读取的;6、7是等待接收的;8、9是已经接收,但是还没有ACK的

    当前的状态

    • 1、2、3都没有问题,双方达成一致
    • 4和5接收方说自己已经发送了ACK了,但是发送方还没有收到,这个ACK包可能丢了,也可能还在路上
    • 6、7、8、9肯定都发送了,但是只有8、9到了,6、7还没有到达,出现了乱序,这个时候只能在接收方缓存着但是没有办法ACK

    确认和重发机制

    假设4的ACK到了,不幸的是5的ACK丢了,6、7的数据包丢失了,这应该怎么做?

    超时重试

    对每一个发送了,但是没有ACK的包,都设有一个定时器,超过了一定的时间就重新尝试,但是这个超时的时间如何进行评估呢,这个时间不宜过短,时间必须大于往返时间RTT,否则将会引起不必要的重传,也不宜过长,这样的超时时间变长,访问就变慢了

    RTT(Round-Trip Time): 往返时延。在计算机网络中它是一个重要的性能指标,表示从发送端发送数据开始,到发送端收到来自接收端的确认(接收端收到数据后便立即发送确认),总共经历的时延。

    估计往返时间需要TCP通过采样RTT的时间,然后进行加权平均,计算出来一个值,并且这个值还是随着网络的状况不断变化的,我们成为自适应重传算法

    如果过一段时间,5、6、7都超时了,就会重新发送,接收方发现5原来接受过,于是丢弃5;6收到了,发送ACK,要求下一个是7,7不幸又丢了,当7再次超时的时候,有需要重传的时候,TCP的策略是超时间隔加倍,每当遇到一次超时重传的时候,都会将下一次超时时间间隔设为先前的两倍,两次超时就说明网络环境差,不适合频繁反复发送

    超时触发重传存在的问题是,超时周期可能相对较长

    有一个快速重传的机制,当接收方收到一个序号大于下一个所期望的报文段时,就检测到了数据流中的一个间隔,于是发送三个冗余的ACK,客户端收到后,在定时器过期之前,重传丢失的报文段

    例如,接收方发现6、8、9都已经接收了,7还没来,那肯定是丢了,于是发送三个6的ACK要求下一个是7,客户端收到3个ACK就会发现7的包确实又丢了,不再等待超时,马上重发

    SACK,这种方式需要在TCP头加一个SACK的东西,可以将缓存的地图发送给发送方,例如有了ACK6、ACK8、ACK9就会知道7丢了

    流量控制

    在对于包的确认中,同时会携带一个窗口的大小

    假设窗口不变,始终为9,4的确认来的时候,会右移一个,这个时候第13个包也可以发送了

    image

    这个时候,假设发送端发送过猛,会将第三部分的10、11、12、13全部发送完毕,之后就停止发送了,未发送可发送部分为0

    image

    当对于包5的确认到达的时候,在客户端相当于窗口滑动了一格,这个时候才可以有更多的包可以发送了,接下来14可以被发送

    image

    如果接收方实在处理太慢,导致缓存中没有了空间,可以通过确认信息修改窗口的大小,甚至可以设置为0,让发送端暂时停止发送

    假设接收端应用一直不读取缓存中的数据,当数据包6被确认后,窗口大小就会减小一个变为8

    image

    这个时候可以看到,接收端的窗口并没有向右移动,只是简单地将左边的标记右移一格,窗口大小变为8

    image

    如果接收端一直不处理数据,则随着确认包越来越多,窗口越来越小直到为0

    image

    如果情况变成这样,发送方会定时发送窗口探测数据包,看看是否有机会调整窗口的大小,当接收方比较慢的时候,要防止低能窗口综合征,不要空出一个字节就告诉发送方,然后立马被填满,可以当窗口太小的时候,不更新窗口,直到达到一定大小,或者缓冲区一般为空的时候再更新窗口

    拥塞控制

    拥塞控制同样通过窗口的大小来控制,滑动窗口是为了防止发送方把接收方缓存塞满,而拥塞窗口是为了不把网络填满

    LastByteSent - LastByteAcked <= min{滑动窗口, 拥塞窗口}

    TCP协议是不知道真个网络路径都是什么,TCP包常被比喻为往一个谁管理灌水TCP拥塞控制就是在不堵塞,不丢包的情况下,尽量发挥带宽

    网路通道的容量 = 带宽 x 往返延迟

    image

    假设往返时间为8s,发送的过程4s,返回的时间4s,每个包1024byte,过了8s,8个包都发出去了,其中4个已经到达了接收端,但是ACK还在路上,不能算是发送成功了,5-8后四个包还在路上没被接收,这个时候,整个管道刚好被撑满

    如果我们在这个基础上再将窗口调大一点,会出现什么现象?

    如果从发送端到接收端会经过四个设备,每个设备处理包的时间需要1s,所以4个包的话,总共的处理时间为4s,如果窗口调大,也就有可能增加发送速度,单位时间内,会有更多的包到达这些中间设备,那么处理中的设备会丢弃到多余的包,这是我们不想看到的

    这个时候,我们可以为这四台设备增加缓存,处理不过来的包在队列里等待,这样就不会丢失了,但是缺点是会增加时间,在之前我们分析过只需要4s一个包即可到达发送端,但是进入缓存中多余的包肯定到达的时间是要超过4s的,如果这个时候发送方还是没有收到ACK那么就会触发超时重传,TCP的拥塞控制就是为了处理包的丢失和超时重传

    一条TCP连接的开始,cwnd设置为一个报文段,一次只能发送一个,当收到这个确认的时候,cwnd +1,于是一次能够发送2个,当这两个的确认到来的时候,每个确认的cwnd + 1 ,两个确认的cwnd就可以 +2,现在可以发送4个, 这是指数级别的增长,但是有一个值sshthresh为65535字节,当超过这个值的时候不要增长得这么快了,可能快满了,再慢下来

    于是,每收到一个确认后,cwnd增长1/cwnd,一共发送8个的话,当8个确认到来的时候,每个确认增加1/8,八个确认一共cwnd + 1,于是一次能够发送9个,变成了线性增长,但是肯定有一天会满,这个时候就会出现拥堵,就需要慢慢等待包的处理

    拥塞的一种形式是丢包,需要超时重传,这个时候

    • 将sshthresh设为cwnd/2
    • 将cwnd设为1

    重新开始慢启动,这样的话,只要超时重传就感觉会回到解放前

    快速重传,当接收端发现丢了一个中间包的时候,发送三次前一个包的ACK,于是发送端就会快速重传,不必等待超时再重传,TCP认为这种情况不严重,因为大部分没丢,只丢了一小部分

    • cwnd减半为cwnd/2
    • sshthresh变为cwnd
    • 当3个包返回的时候,cwnd变为sshthresh + 3
    超时重传和快速重传

    正是这种知道该快还是慢的情况下,使得时延很重要的情况下,反而降低了速度,但是拥塞控制还是存在问题

    1. 第一个问题是,丢包并不代表是网络拥堵了导致设备不能处理多余的包主动丢弃,但是这个时候如果我们认为是拥塞了,是不合适的

    2. 第二个问题是,TCP的拥塞控制要等到将中间设备都填充满了才会丢包,降低速度,这个时候其实已经晚了,只要TCP填满管道就好了,没必要接着填

    为了优化这两个问题,有了TCP BBR拥塞算法,它企图找到一个平衡点,通过不断的加快发送速度,将管道填满,但是不会填满中间设备的缓存,因为这样时延会增加,这个平衡的时点可以很好的达到高带宽和低时延的平衡

    超时重传和快速重传

    相关文章

      网友评论

          本文标题:TCP和UDP的区别

          本文链接:https://www.haomeiwen.com/subject/ntktfqtx.html