面向连接的运输: TCP 《计算机网络——自顶向下方法(James F. Kurose, Keith W. Rose)》读书笔记

         TCP连接是因特网运输层的面向连接(connection-oriented)的可靠运输协议。

一、TCP连接

 (1)TCP被称为面向连接的协议,是因为在两个应用程序互相发数据之前,必须先进行握手建立连接。这种连接不是一条像在电路交换网络中的TDM或FDM电路,也不是一条虚电路——因为TCP协议只在端系统中运行,所以他们的连接状态完全保留在端系统中,而中间的网络元素(路由器等)不会维持、也不知道他们的连接状态。

(2)TCP连接提供全双工服务(full-duplex service),即当两个进程A和B建立起TCP连接之后,那么应用层数据可以在从A流向B的同时,也从B流向A。

(3)TCP连接是点对点的连接。即在单个发送方与单个接收方之间的连接。多播(即在一次发送中,从一个发送方将数据传输给多个接收方)对TCP来说是不可能实现的。

        我们将发起TCP连接的进程叫作客户进程,而另一个进程称为服务器进程。当客户进程想要与服务器进程建立连接时,它首先发送一个特殊的TCP请求报文——>服务器进程收到后,回送一个特殊的TCP响应报文——>客户进程再发一个TCP响应报文(最后这个 报文可以承载有效载荷)。这时,两边都已经收到响应报文,三次握手(three-way handshake)连接建立。在三次握手连接建立中,连接的双方都将初始化与TCP连接相关的许多状态变量。

        一旦TCP连接建立,两个进程之间就可以发送数据了。客户进程的应用层将要发送的数据流传递到套接字(进程之门)后,数据流就由TCP协议管了。它将引导数据流到TCP发送缓存中(这个发送缓存是在三次握手期间初始化的),然后根据最大报文段长度(Maximum Segment Size,MSS)来决定一次应当取多大的数据放入报文段中。当TCP连接的另一端接收到报文段之后,该报文段的数据就被提取出来放入TCP接收缓存中(这个缓存也是握手期间初始化的)。应用程序从此缓存读取数据。

面向连接的运输: TCP 《计算机网络——自顶向下方法(James F. Kurose, Keith W. Rose)》读书笔记_第1张图片

这边有两个比较常见的名词:

①最大报文段长度(Maximum Segment Size,MSS):该术语很容易被混淆,它其实指的是报文段里应用数据的最大长度,而不是包括TCP首部的TCP报文段的最大长度。

②最大传输单元(Maximun Transmission Unit,MTU):指的是最大链路层帧长度,即应用数据+TCP首部+IP首部

至此,我们知道了TCP连接的组成包括:两台主机上的缓存、变量和与进程相连的套接字。而两台主机之间的网络元素(路由器、交换机和中继器)没有为该连接分配任何变量。

二、TCP报文结构

        TCP报文结构由一个首部字段和一个数据字段组成。其中,首部字段有20字节的典型长度+一个可选的“选项”字段组成;而数据字段的长度由MSS决定。

TCP的首部包含:

    ①源端口号和目标端口号:被用于多路复用来自上层应用的数据/多路分解送到上层应用

    ②32比特的序号字段和32比特的确认字段:这些字段被TCP发送方和接收方用来实现可靠数据传输服务(讨论见后)

    ③16比特接收窗口字段:该字段用于指示接收方愿意接收的字节数量,用于流量控制

    ④4比特的首部长度字段:指示以32比特的字为单位的TCP首部长度(如典型的TCP长度(20字节)的首部长度是5)

    ⑤可选与变长的选项字段:该字段用于发送方与接收方协调最大报文长度(MSS)时,或在高速网络环境下用作窗口调节因子时使用。

    ⑥6比特的标志字段:ACK(确认反馈),RST、SYN、FIN(用于连接的建立和拆除),【PSH(指示接收方应立即将数据交给上层),URG(报文里存在着被发送端上层设为紧急的数据,紧急数据的最后一个字节由一个16比特的紧急数据指针指出)】在实践中,PSH和URG并没有使用。

具体的TCP报文结构见图2:

面向连接的运输: TCP 《计算机网络——自顶向下方法(James F. Kurose, Keith W. Rose)》读书笔记_第2张图片

下面,介绍TCP报文结构中比较重要的几个字段。

(1)序号和确认号。

            在TCP协议中,序号是对应用层所要发送的数据的字节流的编号,而不是对报文段的编号。举例来说,进程A想要想进程B发送50000字节的数据,而其MSS为1000字节。那么,在TCP协议中,第一个报文段的序号是0,第二个报文段的序号是1000,第三个报文段的序号是2000......以此类推。序号表示的是:当前的报文段中应用层数据的首个字节在整个字节流中的位置。如图3所示:

面向连接的运输: TCP 《计算机网络——自顶向下方法(James F. Kurose, Keith W. Rose)》读书笔记_第3张图片

        现在讨论一下确认号。前面讲过,TCP连接是全双工的,也就是说,当主机A向主机B发送数据的同时,他也有可能受到来自主机B的数据。举例来说,A收到了B发送的0~535的报文,同时它打算发送一个报文给B,那它的发送的这条报文的确认号将为536,表示它希望下一个接收到的报文的第一个序号是536 (当然,这条报文的初始序号是主机A自己随机选择的,比如0)。值得注意的是,由于TCP提供累计确认,它的报文中的确认号只会包含该数据流中第一个丢失的字节为止的字节。也就是,如果A接收到了0~535的报文后,又接收到了第三个报文段900~1435 ,也就是说,第三个报文段失序到达了。这时候,接收方会返回最小的未收到确认号:536,请求第二个报文(而绝不会请求第四个报文)。

而对于失序的报文段,TCP将处理权交给了程序员。程序员有两种选择:①立即丢弃失序报文;②保留失序报文,并等待缺失的字节来填充该空缺。显然,后一种对实际带宽而言更为有效,是在实践中采用的方法。

            在图3中,我们假设初始序号为0,事实上,TCP连接的双方都可以随机选择初始序号。这样做可以降低上一条TCP连接残留在网络中的报文段误认为是新的连接里的报文段的可能性(如果这两个连接恰好使用了同一个端口的话)

        下面,以一个Telnet的例子来更加深刻地理解序号和确认号。

telnet是现在一个用于远程登录的流行应用层协议,它运行在TCP协议上。当主机A发起一个与主机B的Telnet对话,主机A被标位客户端,B被标记为服务器,A在键盘敲入的每个字符都会被发送到远程主机B,然后B将会回送字符的副本给A。

现在假设客户端A的起始序号是42,服务器B的起始序号是79。在客户端中中输入一个字符‘c’,那么从A发出的报文应该是一个序号=42,确认号=79,data='c' 的TCP报文(前面说过,确认号指的是期待收到的下一个字节序号。在双方还没开始互发数据之前,客户端A等待的是79,而服务端B等待的是42)。如图4所示:

面向连接的运输: TCP 《计算机网络——自顶向下方法(James F. Kurose, Keith W. Rose)》读书笔记_第4张图片

        第一个报文段是由客户端A发往服务器端B的,它的数据字段里包含一个字符‘c’。如刚才所讲的,客户第一次发送报文段,所以它的序号是42,由于还没有从服务器端收到报文,所以它的确认号是79

        第二个报文是由服务器端向客户端发送的。首先,它是为从客户端收到的数据提供一个确认(数据的长度是1,所以确认号是42+1);并且,这个报文段的目的是向客户端回送一个字符‘c’,所以在它的数据字段里包含一个字符‘c’,序号是它的起始序号=79;多提一句,对客户端到服务器的确认被装载到一个承载着服务器到客户端的数据的报文段中,这种确认成为是被捎带(piggybacked)的。

        第三个报文段是从客户端发向服务器的,它的唯一目的是确认已从服务器收到的数据。该报文段的确认号是80,表示它期待从服务器中收到80号的数据。尽管报文段本身没有携带数据,它的序号仍需要被填进去(43),因为这是报文段的首部结构所要求的。

三、往返时间的估计与超时

        如在可靠数据传输原理中介绍的一样,TCP所采用的也是超时/重传机制来处理报文丢失的问题。

1. 估计往返时间

        报文段的“样本RTT”(SampleRTT)就是指某报文段被发出到该报文段的确认被收到的时间间隔。大多是TCP的实现都是在一定的时刻对某个报文段的SampleRTT进行测量,而不是对每一个报文都进行测量。当然,他们是绝不会测量已被重传过的报文的SampleRTT的(因为可能会收到前一个报文的ACK,造成SampleRTT的误差较大)。

        TCP维护一个SampleRTT的均值EstimatedRTT,每次收到一个新的SampleRTT,就对这个EstimatedRTT进行更新:

                                EstimatedRTT=(1-a)*EstimatedRTT+a*SampleRTT

a的参考值为0.125,即:

                                EstimatedRTT=0.875*EstimatedRTT+0.125*SampleRTT

        值得注意的是,EstimateRTT是一个对SampleRTT的加权平均,每次来了一个新的SampleRTT后,原来旧的SampleRTT的权值就会快速下降:这种加权平均对最近的样本赋予的权值要大于对老样本赋予的权值。从统计学的观点上讲,这种平均被称为指数加权移动平均(Exponential Weighted Moving Average,EWMA)。

        除了估算RTT外,测量RTT的变化也是有价值的。“RTT偏差”(DevRTT)用于估算SampleRTT偏离EstimateRTT的程度:

               DevRTT=(1-b)*DevRTT+b*|SampleRTT-EstimatedRTT|

        注意到DevRTT是一个SampleRTT与EstimatedRTT之间差值的EWMA,所以,当SampleRTT值波动较小的话,DevRTT的值也会很小,如果SampleRTT的波动较大,则DevRTT的值也会很大。b的推荐值是0.25

2. 设置和管理重传超时间隔

        在了解了EstimatedRTT和DevRTT的概念和计算方法之后,我们就可以来设置超时重传的时间间TimeoutInterval了。很显然,TimeoutInterval一定要大于EstimatedRTT,否则几乎每个报文都要重传了。但是,又不能超过太多,不然TCP协议将没有办法快速对丢失的报文进行重传,导致数据传输时延增大。TimeoutInterval应为 EstimatedRTT的值加上一定余量,当SampleRTT与EstimatedRTT之间的波动较大时,这个余量要大些,否则,要小一些。那么,DevRTT就派上用场了:

                   TimeoutInterval=EstimatedRTT+4*DevRTT

        由于SampleRTT是间断性地对进行测量,故EstimatedRTT也是间断性的更新。在EstimatedRTT更新的间隔,如果出现超时事件,TimeoutInterval的值将翻倍,以避免后继的报文过早超时。一旦报文收到并更新EstimatedRTT后,再由上述公式对TimeoutInterval重新计算。

四、可靠数据传输

        由于TCP是在IP不可靠的、尽力而为的服务上建立的一种可靠数据传输协议,即确保接收端从其接受缓存中读取到的数据是无损坏、无间隔、非冗余和按序的。但TCP的报文是被IP数据报携带着在网络中传输的,有可能会出现比特错误、丢包。失序到达等问题,TCP如何保证数据的可靠性呢?参考我们在《可靠数据传输原理》一文中已经介绍了的超时重传方案,TCP协议的可靠数据传输服务建立在GBN(回退N步)机制上,并进行了性能改善:

1. 在TCP的接收端,维护一个nextrcvseqnum变量,保存接收端下一个要接收的最小有序的报文段的序号。

①当接受到的报文的是正确的并且序号为nextrcvseqnum时,更新接收端的nextrcvseqnum,使nextrcvseqnum = nextrcvseqnum+sizeof(接收到的数据),回送确认号为nextrcvseqnum的ACK

②当接收到的报文是正确的,当序号>nextrcvseqnum时,先将这个报文缓存起来,然后继续回复确认号为nextrcvseqnum的ACK告诉发送方自己现在最想要的是序号为nextrcvseqnum的报文。 

③当接收到的报文是正确的,但序号

④当接受到的报文是错误的,则不管序号是什么,接收端丢弃这个报文,并回复确认号为nextrcvseqnum的ACK

2. 在TCP的发送端,需要为最早发送、未被确认的报文段维护一个baseSend变量来保存其序号和一个定时器来记录其等待时间是否超时。

①当发送端接收到一个确认序号num>baseSend的ACK报文,那么,由于TCP采用的是累积确认机制,所以发送方知道序号<=num的报文都已经正确到达接收端了。所以发送端更新最早发送、未被确认的序号baseSend=num。如果当前还有未被确认的报文段,TCP还要重新启动定时器。

②当发送端接收到一个确认序号=baseSend的ACK报文(当确认序号=baseSend时,说明接收方是为baseSend的上一个报文回送的ACK)时,它的定时器会继续运行,并统计接收到的冗余ACK的数量。当接收到对相同数据的3个冗余ACK时,发送方不等定时器的超时时间,直接快速重传序号为baseSend的ACK报文(可以减少等待超时的时间,提升性能),兵重新启动定时器。

③当发送端接收到一个序号

③当发送端的定时器过期时,还没有收到序号>baseSend的ACK,则发送端重传序号为baseSend的报文,并将定时器的值增加一倍。

TCP的可靠数据传输协议是在GBN的基础上,进行了改造。首先,GBN的接收端不会存储任何失序报文,所以GBN遇到超时事件会直接重传所有未被确认的报文,而TCP中只需重传最小未被确认的报文即可;其次,在TCP中加入了冗余ACK机制,可以实现快速重传,不必每次都等待漫长的超时事件的发生。二者大大提高了传输协议的整体性能。

五、流量控制

        前面提到,TCP连接的每一侧都会为该连接设置一个接收缓存,当TCP收到了一条正确、按序的报文后,它就把这条报文里的数据放入接受缓存中。相关联的应用进程会从这个缓存中读取数据,但不必是数据一到达就读取。事实上,接收方有可能因为正在忙于其他事务,而过了一段很长的时间后才去读取。这时,由于应用程序读取数据相对缓慢,如果发送端发送数据太大、太快的话,容易导致缓存溢出,数据丢失。

        TCP为它的应用程序提供了流量控制服务(flow-control service)以消除发送方使接收方缓存溢出的可能性(TCP的发送端也有可能因为IP网络的拥塞而被遏制,这种形式的控制成为拥塞控制(congestion control),这个主题不在本节讨论)。TCP通过维持一个发送方的接收窗口(recieve window)来提供流量控制服务(由于TCP是全双工协议,所以连接的两端都要维持接收窗口rwnd)。

在接收方中,定义以下变量:

LastByteRead:接收端中应用进程从缓存中读走的最后一个字节序号;

LastByteRcvd:接收端中总网络中接收到并放入接收缓存的最后一个字节;

RcvBuffer:接收端的接收缓存大小

必须满足:LastByteRcvd-LastByteRead

接收窗口用rwnd表示,通过接收缓存可用空间的大小来设置:rwnd=RcvBuffer-(LastByteRcvd-LastByteRead)

        接收方通过把rwnd放入发送给发送方的报文中,来通知发送方自己还有多少可用缓存。而发送方跟踪自己的两个变量:LastByteSent和LastByteAcked,第一个变量代表发送方发送的最后一个字节的序号,第二个变量代表发送方发送最后一个已被确认的字节的序号。注意到这两个变量之间的查:LastByteSent-LastByteAcked表示的是发送方发送到连接但是位被确认的量。发送方必须保证:LastByteSent-LastByteAcked<=rwnd

        对这个方案还有一个小小的接收问题。为了理解这一点,考虑一下的情景。主机B的接收缓存已满,并且B没有什么数据要发给主机A,那么,主机B在给主机A发送了一个rwnd=0后,就不会再发送其他数据了。这时,主机A知道B的接收缓存已经满了,它就不能再发数据。但是过了一阵,主机B的应用进程从接收缓存中读走了数据,B的接收缓存又有了新的空间,但是没有人能通知A!因为他们之间没有交流。。为了解决这个问题,我们规定,当接收方的rwnd为0时,发送方继续发送只有一个字节数据的报文段,这些报文段会被接收方确认。以便发送发能够知道rwnd什么时候会有新的空间。

        最后,提一下UDP,UDP协议不提供流量控制服务。当接收方的应用进程读取数据的速度过慢,接收缓存溢出时,将会丢失报文段。

六、TCP连接管理

        本节主要接收TCP连接的建立和拆除。

1. TCP连接的建立:客户端发起

TCP连接的建立也成为三次握手协议,通过以下三个步骤:

(1)首先,客户端想服务端发送一个特殊的“SYN报文”,这个报文不包含应用数据,但其首部的一个标志位SYN被置为1。另外,客户端会随机选择一个初始序号client_isn,并将此编号放入报文的序号字段中;

(2)一旦服务器接收到SYN报文,服务器为TCP连接分配TCP缓存和变量,并向客户TCP发送允许连接的SYNACK报文。在SYNACK报文中,SYN比特被置为1,首部的确认字段被置为client_isn+1,最后,服务器选择自己的随机起始序号server_isn,放入序号段中。

(3)在收到SYNACK后,客户端也要为自己的TCP连接分配TCP缓存和变量,并且向服务器发送一个报文,这个报文是对服务器的允许连接的一个确认。这个报文段的确认字段为server_isn+1;而由于此时连接已经建立,所以SYN比特被置为0。并且,在这个报文段里,可以携带应用层数据。

具体如图5 所示:

面向连接的运输: TCP 《计算机网络——自顶向下方法(James F. Kurose, Keith W. Rose)》读书笔记_第5张图片

2. TCP连接的拆除

参与TCP连接的两个进程中的任意一个都能终止该连接。假设客户端打算终止连接:

(1)客户TCP向服务器进程发送一个特殊的报文,这个报文首部的FIN标志位被置为1;

(2)当服务器接收到这个报文时,他发送一个回送ACK报文

(3)然后服务器发送它的终止报文,其FIN标志位被置为1

(4)最后,该客户对服务器的终止报文进行确认。此时,这两台主机上用于该连接的所有资源都被释放了。

具体如图6所示:

面向连接的运输: TCP 《计算机网络——自顶向下方法(James F. Kurose, Keith W. Rose)》读书笔记_第6张图片


你可能感兴趣的:(计算机网络,TCO,面向连接的运输)