信道通常指链接信号发送方和接收方的传输线路,包括双绞铜线等物理媒体。在实际的网络传输中,信道是不可靠的,在其上传输的分组可能会损坏或丢失,甚至相对次序都不能保证。网络
TCP 这一 运输层协议 则提供了可靠的数据传输框架解决上述问题,其向上层(应用层)提供面向链接的可靠的服务。而TCP的下层是网络层,网络层提供的尽力而为的服务,也就是说不提供任何质量保证。简单来讲,TCP实现如下两个功能,即“可靠”的概念:传输的数据比特不会受到损坏或丢失;全部数据都是按照其发送顺序进行交付的。框架
在本节中咱们仅讨论单向数据传输(unidirectional data transfer)的状况,介绍可靠传输协议、流水线协议、回退N步、选择重传。函数
rdt_send()
函数,调用数据传输协议的发送方,把数据交付给接收方的较高层。udt_send()
函数,将分组发送到不可靠的信道。rdt_recv()
。rdt
协议向较高层交付数据时,调用deliver_data()
。
有限状态机(FSM) 能够表示有限个状态及在这些状态之间的转移和动做等行为的数学模型,下图即表示发送方和接收方的有限状态机,底层信道是彻底可靠的,发送方和接收方有各自的FSM,每一个FSM都只有一个状态。性能
(图解:FSM描述中的箭头指示了协议从一个状态变迁到另外一个状态。引发变迁的事件显示在横线的上方,事件发生时所采用的运动显示在横线的下方。FSM的初始状态用虚线表示。)spa
rdt_send(data)
事件接收来自较高层的数据发送请求。在完成一次数据发送请求中须要两个动做:
make_pkt(data)
产生)udt_send(packet)
发送到信道中rdt_rcv(packet)
事件从底层信道接收一个分组。在一次数据接收过程当中一样须要两个动做:
extract(packet, data)
产生)deliver_data(data)
动做)如今咱们能够假设在信道传输过程当中分组中的比特可能受损了,在这种比特可能受损的状况下,来看一下如何构造可靠数据传输协议 rdt 2.0。注意如今仍然假定全部发送的分组(即便受损)将按照其发送的顺序被接收,同时信道中的分组也不会丢失。code
接收方收到分组之后,能够向发送方发送确定确认 (ACK) 或否认确认 (NAK) 。这些控制报文可让发送方知道哪些内容被正确接收,哪些内容接收有误并所以须要重复。这种基于重传的可靠数据传输协议被称为自动重传请求 (Automatic Repeat reQuest, ARQ) 协议。blog
ARQ协议须要三个功能来处理分组出错的状况:接口
下图为rdt 2.0 的有限状态机描述图,该数据传输协议(自动重传请求协议)采用了差错检测、确定确认与否认确认。事件
rdt_send(data)
事件时:
sndpkt = make_pkt(data, checksum)
产生一个包含待发送数据且带有校验和的分组udt_send(sndpkt)
发送到信道中rdt_rcv(rcvpkt) && isACK(rcvpkt)
),那么发送方知道最近一个分组已经被正确接收,所以协议返回左边状态,继续等待下一次由较高层传下来的数据发送请求rdt_rcv(rcvpkt) && isNAK(rcvpkt)
),那么发送端知道接收端接收到的分组是受损的,因此调用 udt_send(sndpkt)
从新发送该分组,而后状态不变,继续等待接收接收端的 ACK 或 NAK 分组。在上述协议中,当发送方处于等待ACK或NAK状态时,它不能从上层得到更多数据。这样子的协议被称为停等协议 (stop-and-wait)。资源
rdt_rcv(rcvpkt) && corrupt(rcvpkt)
,则返回 NAK 分组rdt_rcv(rcvpkt) && notcorrupt(rcvpkt)
,则返回 ACK 分组
rdt2.1 彷佛是一个能够在有比特差错信道上正常工做的可靠数据传输协议了,但仔细想一想,咱们没有考虑 ACK 或 NAK 分组受损的状况。
处理ACK/NAK分组损坏的方法有如下三种:
想要解决这个问题,咱们须要在数据分组中添加一个新的字段,而后让发送端对其数据分组编号,将发送数据分组的序号放在该字段中。因而,接收端只须要检查序号就能够肯定收到的分组是不是一次从新传送的分组。
咱们把引入序号的协议称为rdt 2.1
,FSM图以下。
rdt_send(data)
事件,经过 sndpkt = make_pkt(0, data, checksum)
产生一个序号为 0,包含待发送数据且带有校验和的分组,接着经过 udt_send(sndpkt)
将其发送到信道中,而后状态变迁为“等待接收接收端的 ACK 或 NAK 0”udt_send(sndpkt)
从新传送刚才的序号为 0 的分组到信道中rdt_send(data)
事件,经过 sndpkt = make_pkt(1, data, checksum)
产生一个序号为 1,包含待发送数据且带有校验和的分组,接着经过 udt_send(sndpkt)
将其发送到信道中,而后状态变迁为“等待接收接收端的 ACK 或 NAK 1”udt_send(sndpkt)
从新传送刚才的序号为 1 的分组到信道中rdt_rcv(rcvpkt)
从底层信道接收了一个分组数据:
rdt_crv(rcvpkt) && corrupt(rcvpkt)
),那么由 sndpkt = make_pkt(NAK, checksum)
产生一个附带校验和的 NAK 分组,接着由 udt_send(sndpkt)
发送回发送端rdt_rcv(rcvpkt) && notcorrupt(rcvpkt) && has_seq1(rcvpkt)
),那么由 sndpkt = make_pkt(ACK, checksum)
产生一个附带校验和的 ACK 分组,接着由 udt_send(sndpkt)
发送回发送端rdt_rcv(rcvpkt) && notcorrupt(rcvpkt) && has_seq0(rcvpkt)
),那么经过 extract(rcvpkt, data)
和 deliver_data(data)
将分组数据上传给较高层程序。接着,由 sndpkt = make_pkt(ACK, checksum)
产生一个附带校验和的 ACK 分组,由 udt_send(sndpkt)
发送回发送端
协议rdt 2.1 使用了确定确认和否认确认。当接收到正确的分组时,接收方发送一个“确定确认”,当接收到受损的分组时,发送一个“否认确认”。若是不发送NAK,而是对上次正确接收的分组发送一个ACK,也能够实现同样的效果。发送方若是接收到两个同样的ACK,就说明接收方没有正确接收到跟在被确认两次的分组后面的分组。
咱们把只使用ACK的协议称为rdt 2.2
,其FSM图以下。
具体 rdt 2.2 的流程由于和 rdt 2.1 基本相似,故不赘述。
在现实的网络环境中,除了比特受损外,底层信道还会丢包;有不少可能的方法能够解决丢包问题,这里咱们让发送方负责检测和恢复丢包工做。
假定发送端传输一个数据分组,该分组发生丢失 或者 接收端对该分组的 ACK 发生了丢失。在这两种状况下,发送端都收不到应当到来的接收端的响应。因此,若是发送端愿意等待足够长的时间以肯定该分组缺失已丢失,则它只须要重传该数据分组便可。
从发送端的观点来看,重传是一个万能灵药。为了实现基于时间的重传机制,须要一个倒数计时器 (countdown timer),在一个给定的时间量过时以后,可中断发送方。发送方须要作到:1)每次发送一个分组(包括第一次分组和重传分组)时,就启动一个定时器;2)相应定时器中断;3)终止定时器。
下图是rdt 3.0
的发送方FSM,该协议运行在可能发生出错和丢失的信道上。
rdt 2.2 协议中的接收端有限状态机描述图仍然适用于 rdt 3.0 协议,下面我仍然用文字来简要描述一下上图中的发送端发送分组流程:
rdt_send(data)
事件,经过 sndpkt = make_pkt(0, data, checksum)
产生一个序号为 0,包含待发送数据且带有校验和的分组,接着经过 udt_send(sndpkt)
将其发送到信道中并启动定时器,而后状态变迁为“等待接收接收端的 ACK 0”corrupt(rcvpkt)
)或者收到了 ACK 1(即 isACK(rcvpkt, 1)
,也就是收到了本身发送的上一个分组的 ACK),则直接忽略udt_send(sndpkt)
从新发送该分组并从新启动定时器
假设有两台主机,分别位于美国西海岸和东海岸,端对端延时 大约为 30ms,假定它们经过一条速率 R 为 1Gbps 的信道相连。包括首部字段和数据的分组长 L 为 1KB (8000 bits),因此发送一个分组进入 1Gbps 链路实际所需
若是发送方在 t=0 时刻开始发送分组,则在 8μs 后,最后1bit进入了发送端信道。通过 15ms 后,分组的第一个 bit 到达接收端;在 15.008ms 时刻,分组的最后一个 bit 到达接收端。假设接收端的 ACK 产生和发送不占用时间,则再通过 15ms 之后,即t=30.008ms,发送端接收到接收端的ACK,发送端能够发送下一个分组。
在 30.008ms 内,发送方的发送使用了0.008ms。咱们定义信道利用率为:发送方实际忙于发送比特到信道的时间与发送时间之比,则中止等待协议的发送方利用率为:
在1G连路上每30毫秒才发送一个分组(33KB/s),这就是网络协议限制了物理资源的利用的例子。
校验和、序号、定时器、确定和否认确认分组,这些技术都在协议的运行中起到了必不可少的做用。如今 rdt 3.0 已是一个功能正确的协议,但由于它的本质仍然是停等协议,因此效率实在捉急。在本笔记的下篇中,将介绍流水线可靠数据传输协议、回退 N 步协议以及选择重传协议,最终将会获得一个可靠而且效率较高的协议实现方法。