TCP协议特点
TCP是TCP/IP体系中非常复杂的一个协议。下面介绍TCP最主要的特点。
- TCP是面向连接的运输层协议。这就是说,应用程序在使用TCP协议之前,必须先建立TCP连接。在传送数据完毕后,必须释放己经建立的TCP连接。
- 每一条TCP连接只能有两个端点(endpoint),每一条TCP连接只能是点对点的(一对一)。这个问题后面还要进一步讨论。
- TCP提供可靠交付的服务。通过TCP连接传送的数据,无差错、不丢失、不重复,并且按序到达。
- TCP提供全双工通信。TCP允许通信双方的应用进程在任何时候都能发送数据。TCP连接的两端都设有发送缓存和接收缓存,用来临时存放双向通信的数据。在发送时,应用程序在把数据传送给TCP的缓存后,就可以做自己的事,而TCP在合适的时候把数据发送出去。在接收时,TCP把收到的数据放入缓存,上层的应用进程在合适的时候读取缓存中的数据。
- 面向字节流。TCP 中的**“流”(stream)指的是流入到进程或从进程流出的字节序列**。TCP把应用程序交下来的数据仅仅看成是一连串的无结构的字节流。接收方的应用程序必须有能力识别收到的字节流,把它还原成有意义的应用层数据。
总结成一句话可以是:TCP是面向字节流的,可靠的,点对点的全双工面向连接协议。
连接的概念
TCP把连接作为最基本的抽象。每一条TCP连接有两个端点。那么,TCP连接的端点是什么呢?不是主机,不是主机的IP地址,不是应用进程,也不是运输层的协议端口。
- TCP连接的端点叫做套接字(socket)或插口。根据RFC 793的定义:端口号拼接到(concatenated with) IP地址即构成了套接字。因此,套接字的表示方法是在点分十进制的IP地址后面写上端口号,中间用冒号或逗号隔开。例如,若IP地址是192.3.4.5而端口号是80,那么得到的套接字就是192.3.4.5:80。
每一条TCP连接唯一地被通信两端的两个端点(即两个套接字)所确定即:
- TCP连接定义为:
{socket1, socket2}={(IP1: port1), (IP2: port2)}
这里IP1和IP2分别是两个端点主机的IP地址,而port1和port2分别是两个端点主机中的端口号。TCP连接的两个套接字就是socket1和socket2。可见套接字socket是个很抽象的概念。
一定要记住:TCP连接的端点是个很抽象的套接字,即(IP地址:端口号)
。也还应记住:同一个IP地址可以
有多个不同的TCP连接,而同一个端口号也可以出现在多个不同的TCP连接中
可靠传输的原理
TCP发送的报文段是交给IP层传送的。但IP层只能提供尽最大努力服务,也就是说,TCP下面的网络所提供的是不可靠的传输。因此,TCP必须采用适当的措施才能使得两个运输层之间的通信变得可靠。
我们可以使用一些可靠传输协议,当出现差错时让发送方重传出现差错的数据,同时在接收方来不及处理收到的数据时,及时告诉发送方适当降低发送数据的速度。这样一来,本来不可靠的传输信道就能够实现可靠传输了。下面从最简单的停止等待协议讲起
停止等待协议
全双工通信的双方既是发送方也是接收方。下面为了讨论问题的方便,我们仅考虑A发送数据而B接收数据并发送确认。因此A叫做发送方,而B叫做接收方。因为这里是讨论可靠传输的原理,因此把传送的数据单元都称为分组,而并不考虑数据是在哪一个层次上传送的。停止等待就是每发送完一个分组就停止发送,等待对方的确认。在收到确认后再发送下一个分组:
- 无差错的情况
- 出现差错的情况,超时重传
- 确认丢失和确认迟到
以上过程中需要注意:
- A在发送完一个分组后,必须暂时保留已发送的分组的副本(在发生超时重传时使用).只有在收到相应的确认后才能清除暂时保留的分组副本。
- 分组和确认分组都必须进行编号。这样才能明确是哪一个发送出去的分组收到了确认,而哪一个分组还没有收到确认。
- 超时计时器设置的重传时间应当比数据在分组传输的平均往返时间更长一些。
当发送方发的报文有差错或者接收方给的确认丢了或来晚了的情况下,通过以上的停止等待协议即可正确处理问题,使用上述的确认和重传机制,我们就可以在不可靠的传输网络上实现可靠的通信。
像上述的这种可靠传输协议常称为自动重传请求ARQ (Automatic Repeat reQuest)。意思是重传的请求是自动进行的。接收方不需要请求发送方重传某个出错的分组,为了提高传输效率,发送方可以不使用低效率的停止等待协议,而是采用流水线传输
连续ARQ协议
滑动窗口协议比较复杂,是TCP协议的精髓所在。下图是发送方维持的发送窗口,它的意义是:位于发送窗口内的5个分组都可连续发送出去,而不需要等待对方的确认。这样,信道利用率就提高了。分组发送是按照分组序号从小到大发送的
发送方收到了对第1个分组的确认,于是把发送窗口向前移动一个分组的位置.如果原来已经发送了前5个分组,那么现在就可以发送窗口内的第6个分组了。这种方式有优点也有缺点:
- 优点:接收方一般都是采用累积确认的方式。这就是说,接收方不必对收到的分组逐个发送确认,而是在收到几个分组后,对按序到达的最后一个分组发送确认,这就表示:到这个分组为止的所有分组都己正确收到了
- 缺点:如果传输过程中,中间某一分组丢失,那么,丢失分组后面的数据也都需重传
在深入讨论TCP的可靠传输问题之前,必须先了解TCP的报文段首部的格式
TCP的重要特性
这部分讨论TCP的重要特性:可靠传输、拥塞控制以及TCP连接
TCP可靠传输的实现
我们假定数据传输只在一个方向进行,即A发送数据,B给出确认。这样的好处是使讨论限于两个窗口,即发送方A的发送窗口和接收方B的接收窗口
滑动窗口实现方式
滑动串口按照如下的方式步骤实现:
- B将确认号31告知A,然后A从该确认号开始,发送后边的窗口大小的数据
- 如果此时32,33没有按序到达,说明31没有收到,所以B仍然只能给A返回确认号仍然是31
- 如果31,32,33都顺利到达,A收到了新的确认号34,则滑动窗口向前移动3
4. 如果A在连续发送完42-53之后,P2和P3重合,发送窗口内的序号都已经用完了,但还没有再收到确认,这样A就等待一段时间(重传计时器控制)后就重传这部分数据,重新设置重传计时器,直到收到B的确认为止。
以上有几个指针标识的区间如下:
- P3-P1 = A的发送窗口大小
- P2-P1 = 已发送但还没有收到确认的
- P3-P2 = 允许发送但还没有发送的
需要注意的是,窗口大小是可变的。发送方的发送窗口不能超过接收方给出的接收窗口的数值
发送缓存和接收缓存
发送缓存用来暂时存放: (1)发送应用程序传送给发送发TCP 准备发送的数据; (2)TCP已发送出但尚未收到的确认的数据。
接受缓存用来暂时存放: (1)按序到达的、但尚未被接受应用程序读取的数据; (2)未按序到达的数据。
应用进程把数据传送到TCP的发送缓存后,剩下的发送任务就由TCP来控制了。可以用不同的机制来控制TCP报文段的发送时机。
- 第一种机制是TCP维持一个变量,它等于最大报文段长度MSS。只要缓存中存放的数据达到MSS字节时,就组装成一个TCP报文段发送出去。
- 第二种机制是由发送方的应用进程指明要求发送报文段,即TCP支持的推送(push)操作。
- 第三种机制是发送方的一个计时器期限到了,这时就把当前已有的终存数据装入报文段(但长度不能韶过MSS)发送出去
以上三种方式对TCP的传输效率至关重要。
超时重传时间的选择
快了,频繁的重传可能是重复工作,无用却挤占信道;慢了,传输已经出了问题,发送方和接收方还在等。超时重传时间或大或小都会影响传输效率。但可以肯定的是:超时重传时间设置要比数据报往返时间(往返时间,简称RTT)长一点
RTTS报文往返时间
TCP采用了一种自适应算法,它记录一个报文段发出的时间,以及收到相应的确认的时间。这两个时间之差就是报文段的往返时间RTT。TCP保留了RTT的一个加权平均往返时间RTTs(又称为平滑的往返时间)。
新的RTTs = (1-α) * (旧的RTTs)+α * (新的RTT样本) 0≦α<1
RFC推荐的 α 值为1/8,即0.125。通过上面的公式得出的加权平均往返时间RTTS就比直接测量得出的RTT更加平滑,换句话说,新RTTS就是由7/8的旧RTTS和当前1/8的RTT(测量的新RTT样本)相加得出的。
值得注意的是,如果 α 的取值越小,那么RTTS更新相对较平稳;反之 α 的值越接近于1,则RTTS更新浮动较大
超时重传时间
RTO = RTTs +4 * RTTd (RTTd是RTT的偏差的加权平均值) 新的RTTd=(1-β)*(旧的RTTd)+β*|RTTs-新的RTT样本| (β的推荐值是0.25)
选择确认SACK
可以看到上图中的重传使用了悲观的方式,如果第一个片段丢失而后面其他片段都接收到了,重传之后所有片段。若收到的报文段无差错,只是未按序号,中间还缺少一些序号的数据,那么能否设法只传送缺少的数据,而不重传已经正确到达接收方的数据? 答案是可以的。选择确认就是一种可行的处理方法,但是并不常用,因此大多数的实现还是重传所有未被确认的数据块
TCP的流量控制
流量控制(flow control)就是让发送方的发送率不要太快,要让接受方来得及接收。利用滑动窗口机制可以很方便地在TCP连接上实现对发送方的流量控制。发送方的发送窗口不能超过接收方给出的接收窗口的数值。TCP的窗口单位是字节,不是报文段。