可靠传输的TCP
TCP的可靠传输靠什么保证的,TCP可靠传输面临什么问题,TCP的连接和断开。
TCP和UDP都是应用层之下的协议,都是用来提供端到端的传输服务。那么TCP
和UDP有什么不同。以上都是对TCP协议的一些问题,下面慢慢展开来说。
TCP是面向连接的
TCP是面向连接的,这个问题看到过很多次,每次都有过思考,连接代表什么,
是虚拟电路?这样理解的话,那UDP也在通信过程中建立了一个虚拟电路啊。
很明显,这样的解释并不合理。
那么该如何理解这个连接的意思呢。追本溯源,先看看一下TCP和UDP是怎么
定义的。
UDP:
(1)udp是无连接的,发送数据之前不需要建立连接
(2)udp使用尽最大努力交付,即不保证可靠交付,因此主机不需要维持
复杂的连接状态表
(3)udp是面向报文的,对应用层交下来的报文,添加首部就交付IP层。
TCP:
(1)tcp是面向连接的
(2)tcp连接是1对1的
(3)tcp提供可靠交付的服务,通过TCP连接传送的数据,无差错,不丢失
不重复,并且按序到达。
这里仔细思考一下,tcp可以让传输的数据有序,无差错,不丢失。如果直接
传输,可以保证达到这样效果吗?肯定不可以啊,这里双方都应该保存通信的
状态,哪些数据已经传输了,哪些数据丢失了,哪些数据还没有传输过来,这
都需要双方记录下来(为什么双方,因为tcp是全双工通信,可以作为接受端,
也可以作为发送端),如果数据已经传输了,发送方可以把数据从缓存中清除,
如果数据丢失了,数据丢失了,接收方要通知发送方重传。这些状态都是需要
保存的,对状态的保存就是TCP连接的含义。同样,UDP不需要保存这些状态
所以,UDP是无连接。(当下理解,有错再改)
TCP怎么建立连接
那么根据上面的说法,其实建立连接就是对状态的初始化。生出序列号,同样
也有了确认号,并且数据包的大小,发送窗口的大小都在这是做一个初始化。
那么TCP怎么建立连接呢?
TCP建立连接一般经过三次握手,SYN标志位表示申请建立连接,FIN标志位
表示结束连接。
(1)客户端首先发送带有SYN的数据包给服务器端,并且给出自己的序列号。
(2)服务端收到客户端的数据包后,应该给出一个回应,包含确认号。表示
自己已经收到了客户端的连接请求,同时连接应该是双方都需要确认的,服务
端也发送一个带有SYN的数据包,给出自己的序列号,并且和回应放到一个数
据包中,如果能收到客户端的回应,说明双方的通信没有问题。
(3)客户端收到了服务端的回应,就知道了,服务端能够接收自己的数据包,
并且服务端能够正常发送数据包。这时,客户端给出回应。服务端收到后,表
示自己和客户端的通信可以正常进行,连接建立。之后可以正常通信。
为什么是三次握手
因为三次握手已经可以确定双方能够正常通信,这也是能够确认双方能够正常
通信的最小次数。
比如,两个人电话交流。
A:喂,听得到吗?
B:我能听到,你能听到吗?
A:我也能听到。
三次交流才能说明双方的语音的发送和接收都没问题,如果是四次就多了,没
有必要,如果是两次呢?B不确定自己的通话对方能够听到。
为什么不是两次握手
网络环境是复杂的,如果发送端第一次发送的连接请求遇到网络拥塞,超过了
重传时间还没收到回应。发送端会重新发送一个连接请求来建立连接,这个连
接走了一个比较畅通的道路,很快就建立建立,并且完成来通信。但是第一个
连接并没有丢失,而是延时到达了,当它到达的时候,又会建立一次连接,但
是这次连接其实已经过时了,只会平白浪费资源。
如果是三次握手,即使第一个连接延时到达,当它请求连接的时候,因为客户
端已经知道连接已经建立了,会拒绝这次连接。
TCP怎么传输数据
经过上面的一系列步骤,连接终于建立完成了。
在阐述TCP怎么传输数据之前,先来熟悉几个标志位,这几个标志位对于理解
TCP是如何传输数据至关重要。
(1)Seq:序号,用于表示本次发送报文段的第一个字节的序号。
(2)Ack:确认号,用于表示期望下一次接受报文段的第一个字节的序号。
(3)len:本次报文段的长度,seq+len=Ack
为了确保每个数据都能被接受到,就需要对每次的传输进行确认。每发送
一个数据报就进行一次确认。
出现丢包怎么办|停止等待协议
上面的设想是好的,但是网络环境并不是这样的,数据会出现延时或者丢包
如果出现丢包问题该怎么办?
最简单的方法就是发送方确定上一次数据包被接收方收到后,才进行下一次
发送。首先,发送方在发送完数据后给自己一个定时器,如果超过定时时间
还没有收到确认,就重新发送一次。
没有收到确认的情况有两种,一种是自己的数据丢失或者延迟,二是因为确
任丢失或者延迟。
(1)对于发送发放方数据丢失,接收方重新接受发送方重传的数据
(2)对于数据延迟,接收方应该丢弃重复的数据,但是还是要发送确认
(3)对于确认丢失,发送方重传,接收方丢失重复数据,但是要发送确认
(4)对于确认延迟,发送方丢失重复确认就可以了
停止等待
确认丢失
确认延迟
每次只确认一个,效率太低怎么办|滑动窗口协议(ARQ)
每次只发送一个数据包,然后傻傻地等着确认,百无聊赖。珍贵的时间就这样
被消磨了,如果能在等待的时候接着发送数据,想必是极好的。
其实滑动窗口协议就是这样的一个设计初衷,它开始规定一个了窗口大小,可以
连续发送数据包,只要不超过窗口大小就可以。另外,再收到接收方的确认后。
窗口还可以进行滑动。
滑动窗口协议下的确认机制
现在,有了滑动窗口协议,一次可以发送多个数据包,但是接收方的确认机制
是怎么样的呢?是每发一次进行一次确认,还是会累计到一次的次数后进行确
认?
滑动窗口协议规定,发送方每收到一个确认,就把发送窗口向前滑动一个分组
的位置,但是接收方一般都是采用累计确认的方式,也就是说,不用对每一个
分组都发送一个确认,可以在几个分组接受后,对按序到达的最后一个分组进
性确认即可。累计确认优缺点都很明显,不用每一次都发送一个确认,这很
明显节省了带宽。但是如果出现丢包,那么在这个包后面发送的数据要重新
发送一次。
选择确认SACK
上面所说的确认机制在丢包的时候可能要重传已经发送过的数据,那么能不
不能只重传丢包的数据呢?TCP给出了一个解决方案,就是选择确认,接受
方将接收到的数据边界发给发送方,发送方能够推算出丢的包。但是由于TCP
首部的option只有40个字节,每个边界都需要4个字节(32bit),所有
总共可以报告4个已经接受到分组的边界。另外8个字节还需要对SACK做说明。
但是SACK文档并没有说明接收方如果设置SACK,所以一般的选择还是重传
丢包之后所有的数据包。
超时重传的时间确定
超时重传的概念很简单,但是如何确定超时重传的时间呢?计算机网络是分组
交换的,有可能会选择较拥挤的路线,也有可能选择较通畅的路线。如果把重
传时间设置过小,可能会造成不必要的重传。如果超时重传的时间设置的过大,
又可能使网络空闲的时间过大,降低了传输效率。
TCP采用的是一种自适应的算法,它记录一个报文段发出的时间,以及收到相应
确认的时间。这两个时间差就是报文段的往返时间RTT。TCP保留了RTT的一个
加权平均往返时间RTTs.
new RTTs = (1-a)×(old RTTs) + a×(new RTT)
first RTTs = first RTT
a的推荐值为0.125
RTTd是RTT的加权平均值
new RTTd = (1-b)× (old RTTd)+ b × abs(RTTs - new RTT)
first RTTd = half of fisrt RTT
b的推荐值是0.25
RTO = RTTs + 4 × RTTd
TCP流量控制和拥塞控制
TCP如何在复杂的网络环境中进行资源的最大利用,并且又不会增加网络的负担,
如果根据网络环境来选择自己的发送窗口的大小。
发送窗口大小的制约因素
发送窗口肯定不是无限大的,有两个因素在制约着它,一个是接收方的接受
窗口,如果接收方的数据还在处理,没有多余的空间来存放发送的分组,那么
发送的数据就会被丢弃。所以发送窗口的大小要有接收方的接收窗口制约,不
能大于接收方的窗口大小。另外一个就是网络因素,如果网络出现拥塞,应该
适当的减小发送方的窗口,不然只会使得网络环境更加拥塞。
size(发送窗口) < min(size(拥塞窗口,size(接收窗口))
慢启动和拥塞避免
在TCP刚连接开始,本机是不知道网络环境是怎么样的,不知道当前网络环境
是拥塞还是畅通。所以本机只能谨慎向网络中发送数据,先将拥塞窗口设置为
2(RFC推荐MUST be less than or equal to 2*SMSS bytes and
MUST NOT be more than 2 segments.),然后发送2个数据包后会收到
2个确认,把拥塞窗口设置为2+2;然后下一次可以连续发送4个数据包,以此
类推,当拥塞窗口到达慢启动阈值的时候或者侦测到拥塞时,慢启动就结束了。
慢启动阈值
初始的慢启动阈值可以是任意值,启动慢启动算法,当侦测到网络拥塞时,就
可以将慢启动阈值设置为发生拥塞时发送窗口的1/2.之后,只要发生拥塞,就
用上面的方式设置慢启动阈值。
拥塞侦测
在TCP连接中,只要发送的数据超时没有收到确认,就认为网络发生了拥塞。
如果拥塞窗口到达了慢启动阈值,那么接下来就使用拥塞避免算法,在每个
RTT收到确认后会让拥塞窗口增加一个MSS,直到发生拥塞,拥塞窗口重新设置
为一个比较小的值,继续慢启动算法。
快重传与快恢复
快重传是在接收方意识到对方丢包,自己收到了一个乱序的数据包,自己主动
发送多次相同的确认,让发送方尽早知道自己丢包了,然后把丢失的数据包发送
过来,而不是等到重传计时器时间到了再重传。一般是接收方收到乱序的数据
后连续发送三个确认给发送方,发送方连续收到三个重复确认就需要重传丢失
的包。
但是既然能够连续收到三个重复确认,说明网络环境并没有那么糟糕,不然应
该会出现丢包问题,不可能收到三个重复确认。这时候使用慢启动就显得不是
那么合理,所有利用快恢复来解决这个问题。
当方法方连续收到三个重复确认,就把慢启动阈值设置原来阈值的1/2,并且这
拥塞窗口并不是直接设置为1或者2这么小的值,而是也设置为原阈值的1/2,
并且之后使用拥塞避免算法。
在采用快恢复算法的时候,只有在TCP连接建立时和网络出现超时重传时才使
用慢启动算法。
TCP怎么终止连接
TCP终止连接称为四次挥手。
(1)想要结束连接的一方发送带有FIN的数据包
(2)另一方接收到FIN数据包后就发送一个确认。
(3)另一个此时也发送一个FIN数据包
(4)该机接收到FIN数据包后,给出一个确认,这时候连接完全断开。
关于TCP连接和终止连接的问题还有更深入的细节需要讨论,会在其他文章中讨论。