TCP协议要点详解

一、 概述

描述一个网络中各个协议层的方法通常使用国际标准化组织(International Organization for Standardization,ISO)的计算机通信开放系统互连(open system interconnection, OSI)模型,这是一个七层模型,从上至下依次为应用层、表示层、会话层、传输层、网络层、数据链路层和物理层。然而,实际应用中却采用的是TCP/IP模型,它是OSI模型的浓缩版,只有四个层次,分别为应用层(对应OSI的应用层、表示层和会话层)、传输层(对应OSI的传输层)、网络层(对应OSI网络层)和网络接口层(对应OSI数据链路层和物理层)。
TCP、UDP协议就是TCP/IP模型中传输层的两个主要协议,TCP是一个面向连接的协议,为用户提供可靠的全双工字节流,TCP套接字是流套接字(stream socket),TCP关心确认、超时和重传之类的实现细节。
TCP提供客户与服务器之间的连接(connection),TCP客户端先与某个给定的服务器建立一个连接,再跨越该连接与那个服务器交换数据,然后终止这个连接。
TCP连接是全双工的(full-duplex),这意味着在一个给定的连接上应用可以在任何时刻在进出两个方向上既发送数据又接收数据。udp也可以是全双工的。

二、TCP可靠性

TCP提供了可靠性的保证,当TCP由一端和另一端发送数据时,它要求对端返回一个确认(ACK),如果没有收到这个确认,TCP就自动重传数据并等待更长时间。在数次失败后,TCP才放弃重传,如此在尝试发送数据上所花的时间一般为4-10分钟(依赖于具体实现???)。
注意TCP并不保证数据一定会被对方端点收到,因为这是不可能做到的,如果有可能TCP就把数据送递到对方端点,否则就(通过放弃重传并中断这一手段)通知用户,它提供的是数据的可靠递送或者故障的可靠通知。另外,字节流中任何位置的字节丢失都将阻塞该连接上其后所有数据的递送,直到该丢失被修复为止
TCP使用连续ARQ(Auto Repeat Request,自动重发)协议,可以连续发出若干个分组然后等待确认,而不是发送一个分组就停止并等待分组的确认。
TCP含有用于动态估算客户和服务器之间的往返时间(roud-trip time,RTT)的算法, 以便它知道等待一个确认需要多少时间。举例来说,RTT在一个局域网上大约是几毫秒,跨越一个广域网则可能是数秒钟。
另外,由于RTT受网络流通各种变化因素影响,TCP会记录一个给定连接的RTT。 RTT由链路传送时间、末端系统的处理时间和路由器缓存队列中的排队和处理时间。前两个部分对于一个TCP链接相对固定,路由器缓存中排队和处理时间会随着整个网络的拥塞程序的变化而变化,所以RTT的变化在一定程序上反映了网络的拥塞程度。

RTT一般通过下面两种方法计算:

  • TCP TimeStamp选项;

        RTT =   当前时间 -  数据包中TimeStamp回显时间(tsecr)            
    

    这个回显时间是TCP数据包发送出去的时间(接收端收到发送端的报文后进行确认,会在timestamp echo reply字段中转存接收到的报文的发送时间,也称为回显时间)。

  • 重传队列数据包的TCP控制块;
    在TCP重传队列中保存着发送而未被确认的数据包,数据包skb中的TCP控制块包含着一个tcp_skb_cb->when,记录了该数据包第一次发送时间。

对于重传的数据包响应,方法a可以用来作为采集一个新的RTT测量样本,而方法b则不能,因为TCP TimeStamp可以用来区分这个响应是原始数据包还是重传数据包的触发的,从而计算出准确的RTT值。

RTO(retransimission timeout)即重传超时时间,它非常依赖于对一个给定连接的往返时间(RTT)的估算,由于网络流量的变化,RTT值也会相应地发生改变,TCP需要跟踪这些变化并动态调整超时时间RTO。为了给出一个较合理的RTO,我们需要采用数学统计里面的一些方法,用到RTTm(本次测量的RTT值)、RTTs(平滑RTT,相当于一个累积的RTT值的期望)、RTT d(deviation)(偏差,RTTD = |RTTm - RTTs|)

 RTTs = (1 - a) * RTTs + a * RTTm; 
 RTTD = (1 -b) RTTD + b * |RTTm - RTTs|
 RTO = RTTs + 4 * RTTD  

当RTO定时器触发的时候,即所设置的定时时间到达的时候,则在还没有ACK的报文里面重传最早发出去的报文,设置RTO = RTO * 2, 这也是我们经常所说的指数回退,重启定时器,在重传完成后,新的RTT采样可能会将RTO值设为原来比较近的值,从而消除指数回退对于RTO的影响 。
TCP通过给其中每个字节关联一个序列号对所发送的数据进行排序(sequencing),如应用写2048个字节到一个TCP套接字,导致TCP分两个分节发送:第一个分节所含数据的序列号为1-1024, 第二个分节所含数据的序列号为1205-2048。如果这些分节非顺序到达,接收端TCP将先根据它们的序列号重新排序,再把结果数据传递给接收应用。如果接收端TCP接收到来自对端的重复数据(譬如说对端认为一个分节已经丢失并因此重传,而这个分节并没有真正丢失,只是网络通信过于拥挤或者ACK报文丢失),这可以根据序列号判定数据是重复的,从而丢弃重复数据。

三、 流量控制

TCP提供流量控制(flow control), 所谓的流量控制就是控制发送方发送的速率不要太块,让接收方来得及处理。TCP总是告知对端在任何时刻它一次能够从对端接收多少字节的数据,这称为通告窗口(advertised window).在任何时刻,该窗口指出接收缓冲区中当前可用的空间量,从而确保发送端发送的数据不会使接收缓冲区溢出。该窗口时刻变化:当接收到来自发送端的数据时,窗口大小减少;当接收端应用从缓冲区中读取数据时,窗口大小就增大。

四、拥塞控制

TCP的拥塞控制是防止过多的数据注入网络中,这样可以使网络中的路由器或者链路不致过载,因为在某段时间,若对网络中某一资源(如网络中的带宽、交换结点的缓存和处理机等)的需求超过了该资源所能提供的可用部分,网络的性能就会变坏,这种情况叫拥塞。拥塞控制是一个全局性的过程,和流量控制不同,流量控制是点对点的通信流量控制。
发送方维持一个叫做拥塞窗口(congestion window)的状态变量,拥塞窗口的大小取决于网络的拥塞程度,并且动态地变化。发送方让自己的发送窗口等于拥塞窗口,另外考虑到接受方的能力,发送窗口可能小于拥塞窗口。拥塞窗口是发送方使用的流量控制,而通告窗口是接收方使用的流量控制。
慢开始(slow start)算法,通过观察到新分组进入网络的速率应该与另一端返回确认的速率相同而进行工作。其思路就是不要一开始就发送大量的数据,先探测一下网络的拥塞程度,由小到大逐渐增加拥塞窗口的大小。当与另一个网络的主机建立TCP连接时,拥塞窗口被初始化为1个报文段(即另一端通告的报文段大小)。每收到一个ACK,拥塞窗口就增加一个报文段(cwnd以字节为单位,但是慢启动以报文段大小为单位进行增加)。发送方取拥塞窗口与通告窗口中的最小值作为发送上限。发送方开始发送第一个报文段,然后等待ACK。当收到该ACK时,拥塞窗口从1增加为2,即可以发送两个报文段。当收到这两个报文段的ACK时,拥塞窗口就增加为4.这是一种指数增加的关系。
为了防止cwnd增长过大引起网络拥塞,还需要设置一个慢开始门限(ssthresh)状态变量:

a.当cwnd < ssthreash时,使用慢开始算法;  
b.当cwnd > ssthresh时,改用拥塞避免算法;  
c. 当cwnd = ssthreash时,慢开始与拥塞避免算法任意。  

拥塞避免算法让拥塞窗口缓慢增长,即每收到一个ACK包,就把发送的拥塞窗口加1,而不是加倍,这样拥塞窗口按线性规律缓慢增长。
无论是在慢开始阶段,还是在拥塞避免阶段,只要发送方判断网络出现拥塞(超时或者收到重复确认),ssthresh被设置为当前窗口大小的一半(cwnd和接收方通告窗口大小的最小值,但最少为2个报文段)。此外,如果是超时引起了拥塞,则cwnd被设置为1个报文段(这就是慢启动)。
如果一连串的收到3个或者3个以上的重复ACK,就非常可能是一个报文段丢失了,于是我们就重传丢失的数据报文段,而无需等待超时定时器溢出,这就是快速重传算法。接下来执行的不是慢启动而是拥塞避免算法,将ssthresh设置为当前拥塞窗口的cwnd的一半,设置cwnd为ssthresh加上3倍的报文段大小,这就是快速恢复算法。

五、三次握手

TCP三次握手,建立连接:
(a) 服务器端必须准备好接收外来连接,这通常通过调用socket、bind、listen这3个函数来完成,我们称之为被动打开(passive open);
(b) 客户通过调用connect发起主动打开(active open),这导致客户TCP发送一个SYN(同步)分节,它告诉服务器客户端将在(待建立的)连接中发送的数据初始序列号。通常SYN分节不携带数据,其所在数据包只含有一个IP首部、一个TCP首部以及可能有的TCP选项。
(c)服务器必须确认(ACK)客户的SYN,同时自己也得发送一个SYN分节,它含有服务器将在同一连接中发送的数据初始序列号。服务器将在单个分节中发送SYN和对客户的SYN的ACK。
(d)客户必须确认服务器的SYN。
这种交换至少需要3个分节,因此称之为TCP的三次握手(three-hand shake).注意SYN报文中的初始数据序列号是随机值,不一定从零开始,wireshark等捕包工具的序列号是相对值,从0开始。

六、四次握手

TCP四次握手终止连接:
(a) 某个应用进程首先调用close,我们称该端执行主动关闭(active close)。该端的TCP于是发送一个FIN分节,表示数据发送完毕。
(b) 接收到这个FIN的对端执行被动关闭(passive close).这个FIN由TCP确认。它的接收也作为一个文件结束符(end-of-file)传递给接收端应用进程(放在已排除等候该应用进程接收的任何其他数据之后),因为FIN的接收意味着接收端应用进程在相应连接上再无额外数据可接收。
(c) 一段时间后,接收到这个文件结束符的应用进程将调用close关闭它的套接字,这导致它的TCP也发送一个FIN。
(d)接收这个最终FIN的原发送端TCP(即执行主动关闭的那一端)确认这个FIN。
既然每个方向都需要一个FIN和一个ACK,因此通常需要4个分节。我们使用限定词“通常”是因为:某些情形下步骤1的FIN随数据一块发送;另外,步骤2和步骤3发送的分节都出自执行被动关闭的那一端,有可能被合并成一个分节。
类似SYN,一个FIN也占据1 个字节的序列号空间,因此每个FIN的ACK确认号就是个FIN的序列号加1 。
在步骤2和步骤3之间,从执行被动关闭一端到执行主动关闭一端流动数据是可能的,这称为半关闭(half-close)

七、TIME_WAIT状态

TIME_WAIT状态停留的时间是最长分节生命期(maximum segment lifetime, MSL)的两倍,有时候称之为2MSL,理由是:
(a)可靠地实现TCP全双工连接的终止。
如果最终的ACK丢失,服务器将重新发送它的最终那个FIN,因此客户端必须维护状态信息,以允许它重新发送最终那个ACK,要是客户不维护状态信息,它将响应一个RST,该分节将被服务器解释成一个错误。
(b)允许老的重复分节在网络中消逝。
如果某一时刻连接已被关闭,之后在相同的IP地址和端口之间建立另一个连接,后一个连接称为前一个连接的化身(incarnation),因为它们的ip地址和端口号都相同。TCP必须防止来自某个连接的老的重复分组在该连接已终止后再现,从而被误解成属于同一个连接的某个新的化身。为做到这一点,TCP将不给处于TIME_WAIT状态的连接发起新的化身。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值