1.TCP面向连接(三次握手建立);UDP发数据前无需建立连接
2.TCP可靠传输(原理在下面);UDP不保证数据可靠性;
3.TCP面向字节流;UDP面向报文,无拥塞控制,数据发送速率高;
4.TCP只支持点到点;UDP支持多对多,一对多等通信;
udp如何去实现可靠传输?参考以下tcp的结构,①引入序列号,保证数据顺序;②引入确认机制,保证对端收到了数据;③引入超时重传,如果隔一段时间没有应答,就重新发送数据。
tcp传输数据稳定可靠,适用于对网络通讯质量要求较高的场景,需要准确无误的传输给对方。比如,传输文件,发送邮件,浏览网页等等,udp的优点是速度快,但是可能产生丢包,所以适用于对实时性要求较高但是对少量丢包并没有太大要求的场景。比如:语音通话,视频直播等
主机A发送了一个数报给主机B,主机B如果接收到了这个数据包,那么就要给A一个响应(ACK)。
出现差错或丢失的时候,发送方会将自己备份的副本再重传一次,直到收到接收的确认信息;当接收方收到重复的数据时,会直接丢弃,但是会给发送方请确认自己已经收到了。
分两种
主机A作为发送端,B作为接收端,发送端A发出的数据丢了: 主机A没有收到B的响应或者只收到上一个请求的相应(上次的超时重传后),A就认为数据已经丢失了,超时后会再发一遍;
B返回给A的ACK(响应报文段)丢了: A没有接收到B的ACK,A认为数据丢失,就会再发一遍,但是B这边就会接收到两个一样的消息,此时TCP会对相同的消息进行去重处理
为啥要流量控制:接收方应用程序读取数据的速度小于发送方的数据发送速度,将导致接收方的接收缓存溢出,造成数据丢失;首先明确滑动窗口的范畴:
TCP是双工的协议,会话的双方都可以同时接收和发送数据。会话的双方都各自维护一个发送窗口和一个接收窗口。各自的接收窗口大小取决于应用、系统、硬件的限制(TCP传输速率不能大于应用的数据处理速率)。各自的发送窗口则要求取决于对端通告的接收窗口,要求相同。
说明:
1、可以把窗口理解为缓冲区的大小;
2、滑动窗口的大小会随着发送数据和接收数据而变化;
3、通信双方都有发送缓冲区和接收缓冲区;
假设A向B发送数据。在连接建立时,B告诉了A:“我的接收窗口是 rwnd = 400 ”(这里的 rwnd 表示 receiver window) 。因此,发送方的发送窗口不能超过接收方给出的接收窗口的数值。请注意,TCP的窗口单位是字节,不是报文段。假设每一个报文段为100字节长,而数据报文段序号的初始值设为1。这里rwnd是每次服务端发了ACK之后才会去重新计算剩余窗口容量(会有一个初始值),未发送这轮ACK之前,表示这一轮还能接收到的数据剩余容量(也是这轮发送窗口可发送的剩余容量); 而且如果出现数据A丢失的情况,那么A重传(旧数据)将不占用窗口容量;
从图中可以看出,B进行了三次流量控制。第一次把窗口减少到 rwnd = 300 ,第二次又减到了 rwnd = 100 ,最后减到 rwnd = 0 ,即不允许发送方再发送数据了。这种使发送方暂停发送的状态将持续到主机B重新发出一个新的窗口值为止。B向A发送的三个报文段都设置了 ACK = 1 ,只有在ACK=1时确认号字段才有意义。
滑动窗口如何进行流量控制:接收端会在确认应答发送ACK报文时,将自己的即时窗口大小填入,并跟随ACK报文一起发送过去。而发送方根据ACK报文里的窗口大小的值的改变进而改变自己的发送速度。如果接收到窗口大小的值为0,那么发送方将停止发送数据。比如窗口大小值不为0了,发送方将重新开始发送数据;
何时会出现拥塞:数据传输过程中,网络中拥堵的情况,数据包可能会丢失,大量的超时重传继续影响传输出现阻塞;
①慢开始算法:
当主机开始发送数据时,如果立即所大量数据字节注入到网络,那么就有可能引起网络拥塞,因为现在并不清楚网络的负荷情况。因此,较好的方法是,先探测一下,即由小到大逐渐增大发送窗口,也就是说,由小到大逐渐增大拥塞窗口数值。
通常在刚刚开始发送报文段时,先把拥塞窗口 cwnd 设置为一个最大报文段MSS(Maximum Segment Size,最大报文长度)的数值。而在每收到一个对新的报文段的确认后,把拥塞窗口增加至多一个MSS的数值(底数为2的指数增长规律)。用这样的方法逐步增大发送方的拥塞窗口 cwnd ,可以使分组注入到网络的速率更加合理。
一个传输轮次所经历的时间其实就是往返时间RTT。
不过“传输轮次”更加强调:把拥塞窗口cwnd所允许发送的报文段都连续发送出去,并收到了对已发送的最后一个字节的确认。
另,慢开始的“慢”并不是指cwnd的增长速率慢,而是指在TCP开始发送报文段时先设置cwnd=1,使得发送方在开始时只发送一个报文段(目的是试探一下网络的拥塞情况),然后再逐渐增大cwnd。
为了防止拥塞窗口cwnd增长过大引起网络拥塞,还需要设置一个慢开始门限ssthresh状态变量。慢开始门限ssthresh的用法如下:
②拥塞避免
让拥塞窗口cwnd缓慢地增大,即每经过一个往返时间RTT就把发送方的拥塞窗口cwnd加1,而不是加倍。这样拥塞窗口cwnd按线性增长规律缓慢增长,比慢开始算法的拥塞窗口增长速率缓慢得多。
无论在慢开始阶段还是在拥塞避免阶段,只要发送方判断网络出现拥塞(其根据就是没有收到确认),就要把慢开始门限ssthresh设置为出现拥塞时的发送 方窗口值的一半(但不能小于2)。然后把拥塞窗口cwnd重新设置为1,执行慢开始算法。这样做的目的就是要迅速减少主机发送到网络中的分组数,使得发生 拥塞的路由器有足够时间把队列中积压的分组处理完毕。
如下图,用具体数值说明了上述拥塞控制的过程。现在发送窗口的大小和拥塞窗口一样大。
2.快重传和快恢复
③快重传
快重传算法首先要求接收方每收到一个失序的报文段后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方)而不要等到自己发送数据时才进行捎带确认。
接收方收到了M1和M2后都分别发出了确认。现在假定接收方没有收到M3但接着收到了M4。由于可靠传输原理,M3再超时之后会一直进行重发,接收方也会一直重复确认M2(快重传算法规定的)。直到发送方共收到了接收方的四个对M2的确认,后三个都是重复确认。
根据快重传算法规定,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段M3,而不必 继续等待M3设置的重传计时器到期。(这句话意思是发送方可以不用等待下一次M3超时,直接重发M3即可)由于发送方尽早重传未被确认的报文段,因此采用快重传后可以使整个网络吞吐量提高约20%。
如果没有快重传机制
与快重传配合使用的还有快恢复算法,其过程有以下两个要点:
当发送方连续收到三个重复确认,就执行“乘法减小”算法: 把慢开始门限ssthresh减半。
与慢开始不同之处是现在不执行慢开始算法(即拥塞窗口cwnd现在不设置为1),而是把cwnd值设置为 慢开始门限ssthresh减半后的数值,然后开始执行拥塞避免算法(“加法增大”),使拥塞窗口缓慢地线性增大。
概念:mss(最大消息长度)
在建立TCP连接的时候,双方约定一个最大的长度(MSS)作为发送的单位,重传的时候也是以这个单位来进行重传。理想的情况下是该长度的数据刚好不被网络层分块;
几个概念:
1. FIN: 请求关闭报文
2. SYN: 请求建立连接
3. ACK: 确认收到
4. MSL: 最大报文生存时间
第一步: 客户端想要与服务器建立连接, 于是向服务器发送SYN报文请求连接.
第二步: 服务器收到客户端的连接请求之后, 服务器向客户端发送确认报文ACK及请求连接报文SYN
第三步: 客户端收到服务器的连接请求, 向服务器发送确认报文ACK
为什么需要第三次客户端向服务端发送ACK确认请求呢?
三次握手的主要原因是为了防止旧的重复连接引起连接混乱问题。
比如在网络状况比较复杂或者网络状况比较差的情况下,发送方可能会连续发送多次建立连接的请求。如果 TCP 握手的次数只有两次,那么接收方只能选择接受请求或者拒绝接受请求,但它并不清楚这次的请求是正常的请求,还是由于网络环境问题而导致的过期请求,如果是过期请求的话就会造成错误的连接。
所以如果 TCP 是三次握手的话,那么客户端在接收到服务器端 SEQ+1 的消息之后,就可以判断当前的连接是否为历史连接,如果判断为历史连接的话就会发送终止报文(RST)给服务器端终止连接;如果判断当前连接不是历史连接的话就会发送指令给服务器端来建立连接。
第一次挥手:客户端主动请求关闭,并向服务端发送FIN关闭请求;
第二次挥手:服务端收到并发送ACK确认告诉客户端已经收到关闭请求;
第三次挥手:服务端将之前需要发送的数据全部发送完毕后,主动向客户端发送FIN关闭请求;
第四次挥手:客户端收到并发送ACK确认请求,服务端收到ACK后直接关闭;而客户端是不知道服务器是否收到了这次ACK的,客户端这边需要再等待2MSL再进行关闭。如果2MSL内没有收到服务端重发的FIN,默认服务端收到ACK,则客户端关闭;
1. 为什么第二次跟第三次不能合并, 第二次和第三次之间的等待是什么?:
当服务器执行第二次挥手之后, 此时证明客户端不会再向服务器请求任何数据, 但是服务器可能还正在给客户端发送数据(可能是客户端上一次请求的资源还没有发送完毕), 所以此时服务器会等待把之前未传输完的数据传输完毕之后再发送关闭请求.
2. 主动发起方为什么最后要等待2MSL的时间:
上边我们说了服务器收到了最后一次的ACK报文之后就会关闭, 那客户端是不知道服务器是否收到了这次ACK的, 所以客户端只能在这等待, 如果服务器在"超时时间"内真的没有收到最后一次的ACK,就会重新发送一次FIN; 那么在网络极端情况下(网络没断, 但是速度极慢, 需要整整1MSL的时间才能把报文发送过去),这次重发FIN需要1MSL的时间, 这一来一回需要的时间总和为:服务器超时时间+1MSL, 那为了保险起见,直接让客户端等待2MSL的时间, 如果2MSL之内客户端没有收到重发的FIN, 则默认为服务器收到了最后一次ACK,此时客户端就可以执行关闭了.