如何理解TCP的面向连接

编程

TCP/IP高效编程

网络编程中最基本的概念就是面向连接(connection-oriented)和无连接(connectionless)协议
如果两台计算机要进行通信,就必须以某种形式“连接”起来,那“无连接通信”又是什么意思呢?
答案是:面向连接和无连接指的都是协议。这些术语指的并不是物理介质本身,而是用来说明如何在物理介质上传输数据的。面向连接和无连接协议可以,而且通常也确实会共享同一条物理介质。
如果两者的区别与承载数据的物理介质无关,又和什么有关呢?它们的本质区别在于,对无连接协议UDP来说,每个分组的处理都独立于所有其他分组,而对面向连接的协议TCP来说,协议实现则维护了与后继分组有关的状态信息

无连接协议中的分组被称为数据报(datagram),每个分组都是独立寻址,并由应用程序发送的。从协议的角度来看,每个数据报都是一个独立的实体,与在两个相同的对等实体之间传送的任何其他数据报都没有关系。
通常这就意味着客户端和服务器不会进行长期的对话——客户端发起一条请求,服务器回送一个应答。如果稍后客户端发起了另一个请求,协议会认为这是与第一个事务无关的独立事务。这还意味着协议很可能是不可靠的。也就是说,网络会尽最大努力传送每一个数据报,但并不保证数据报不丢失、不延迟或者不错序传输。

另一方面,面向连接的协议则维护了分组之间的状态,使用这种协议的应用程序通常都会进行长期的对话。记住这些状态,协议就可以提供可靠的传输。比如,发送端可以记住哪些数据已经发送出去了但还未被确认,以及数据时什么时候发送的。如果在某段时间间隔内没有收到确认,发送端可以重传数据。接收端可以记住已经收到了哪些数据,并将重复的数据丢弃。如果分组不是按序到达的,接收端可以将其保存下来,知道逻辑上先与它的分组到达为止。
典型的面向连接协议有三个阶段。第一阶段,在对等实体间建立连接。接下来是数据传输阶段,在这个阶段中,数据在对等实体间传输。最后,当对等实体完成数据传输时,连接被拆除。

电话系统有实际的物理连接。而我们的“连接”则完全是想象的——它只是由两端记录的状态构成的。为了说明这一点,我们来看看当一个空闲连接一端的主机崩溃并重启时会发生什么情况。还有连接存在吗?冲重启主机的角度来看,可能没有了。它对先前的连接一无所知。但它原来的对等实体仍然认为自己是连接着的,因为它仍然维护着与连接有关的状态,没有发生什么使那个状态失效的事件。

既然无连接协议有那么多的缺点,大家可能会奇怪,为什么还要使用这种协议呢?我们会看到,在很多情况下,使用无连接协议构建应用程序都是有意义的。比如,使用无连接协议可以很方便地支持一对多和多对一通信,而面向连接协议通常都需要多个独立的连接才能做到。但更重要的是,无连接协议是构建面向连接协议的基础。

TCP/IP基于一个4层的协议栈,栈的底部是接入层,直接与硬件相连。栈的顶部是应用程序,比如Telnet、FTP和其他标准的以及用户编写的应用程序。如图所示,TCP和UDP都是构建在IP之上的。因此,IP是构建整个TCP/IP协议族的基础。但IP提供的是一种尽力而为的、不可靠的无连接服务。它接收来自其上层的分组,将它们封装在一个IP分组(packet)中,根据路由为分组选择正确的硬件接口,从这个接口将分组发送出去。一旦将分组发送出去了,IP就不再关心这个分组了。和所有无连接协议一样,它将分组发送出去之后就不再记得这个分组了。
这种简单性也是IP的主要优点。因为它对底层的物理介质没有作任何假设,所以在任何能够承载分组的物理链路上都可以运行IP.这种机制隐含了很深的意义。IP可以运行在任何能够承载分组的网络上,所以整个TCP/IP协议也可以。

现在我们来看看TCP是怎样利用这种简单的无连接服务来提供可靠地面向连接服务的。TCP的分组被称为端(segment),是放在IP数据报中发送的,因此,根本无法假定这些分组会抵达目的地,更不用说保证分组无损坏且以原来的顺序到达。为了提供这种可靠性,TCP向基本的IP服务中添加了三项功能。首先,它为TCP段中的数据提供了校验和。这样有助于确保抵达目的地的数据在传输过程中不会被损坏。第二,它为每字节分配了一个序列号,这样,如果数据抵达目的地时真的错序了,接收端也能够按照恰当的顺序将其重装起来。
当然,TCP并没有为每字节都附加一个序列号。实际上,每个TCP段的首部都包含了段中第一字节的序列号。这样,就隐含地知道了段中其他字节的序列号。
第三,TCP提供了一种确认-重传机制,以确保最终每个段都会被传送出去。
确认/重试机制是目前为止我们讨论的三种附加机制中最复杂的一种,我们来研究一下它是怎样工作的。
TCP连接的每一端都维护了一个接收窗口(receive window),接收窗口就是可以从对等实体接收的数据序列号范围。最小值表示窗口的左边界,是所期望的下一字节的序列号。最大值表示窗口的右边界,是TCP缓冲区空间所能容纳字节的最大编号。使用接收窗口而不只是所期望的下一字节计数器,就可以通过流量控制来提供可靠性。流量控制机制可以防止TCP传输的数据使其对等实体的缓冲区空间溢出。

TCP段到达时,序列号在接收窗口范围之外的所有数据都会被丢弃。其中包括先前已经收到的数据(序列号在接收窗口左边的数据),以及没有缓冲区空间存储的数据(序列号在接收窗口右边的数据)。如果段中第一个可接收字节不是所期望的下一字节,就说明这个段是错序的,大部分TCP应用程序都会将其放入队列,直到缺少的数据到达为止。如果段中第一个可接收字节是所期望的下一字节,就通知应用程序有数据可读,并在所期望的下一字节序列号上加上段中本次接受的字节数,对其进行更新。此时窗口向右滑动本次接受字节数的长度。最后,TCP向对等实体发送一条ACK,其中携带了它所期望的下一字节序列号。
比如,在图2-2A中,虚线框表示的接收窗口显示,所期望的下一字节序列号为4,而TCP希望接收9字节(4~12)。图2-2B显示的是收到字节4、5、6和7之后的接收窗口。窗口向右滑动了4个序列号,TCP的ACK会说明它接下来所期望的是序列号8。

同样是这种情况,现在从TCP发送端的角度来看。除了接收窗口之外,每个TCP还维护了一个发送窗口(send window)。发送窗口被划分成两部分:已发送但还未被确认的字节,以及可以发送但还未发送的字节。假设字节1~3已经被确认了,图2-3A显示的是与图2-2A中接收窗口相对应的发送窗口。字节4~7发送之后,确认之前,发送窗口如图2-3B所示。TCP还可以发送字节8~12而无须等待来自对等实体的ACK。发送了字节4~7之后,TCP会启动一个RTO(Retransmission Timeout,重传超时)定时器。如果在定时器超时之前这四个字节没有被确认,TCP就认为它们丢失了,并重新传送这四个字节
很多实现并不记录一个特定的段中发送了哪些字节,因此重传段中包含的字节数可能会比原来的多。例如,如果字节8和9在RTO定时器超时之前发送出去了,这些应用程序就会重传字节4~9。

我们要注意这样一个事实:RTO定时器超时并不意味着原来的数据没有到达目的地。有可能是ACK丢失了,或者原来的段在网络中延迟的时间太长,以至于在其ACK达到之前RTO定时器就超时了。但这并不会造成什么问题,因为如果原来的数据确实到达了,那么重传的数据就会处于接收端TCP接收窗口范围之外,会被丢弃。
字节4~7确认后,发送端TCP会将其丢弃,并将发送窗口向右移动,如图2-3C所示。
 

以上是 如何理解TCP的面向连接 的全部内容, 来源链接: utcz.com/z/518896.html

回到顶部