可靠数据协议 计算机网络

2018-11-09 23:00:32 Clark_Fitz817 阅读数 3289

这一周做了一个计算机网络的实验,名字叫 可靠数据传输协议-GBN协议的设计与实现
感觉自己做的很认真,实现的效果也不错,就把自己的过程与结果记录一下

对于这个实验,实验要求上说实现SR协议是加分项,而SR协议又是以GBN协议为基础,所以自己直接一步到位,只实现了 SR 协议(偷了个懒 ) (>ω<)
首先先粘最最重要的资源,包括完整源代码和实验报告 : gitbub项目地址

以下内容截取自实验报告:(提取有用信息)

GBN的原理与实现

原理:

GBN是属于传输层的协议,它负责接收应用层传来的数据,将应用层的数据报发送到目标IP和端口

滑动窗口: 假设在序号空间内,划分一个长度为N的子区间,这个区间内包含了已经被发送但未收到确认的分组的序号以及可以被立即发送的分组的序号,这个区间的长度就被称为窗口长度。(随着发送方方对ACK的接收,窗口不断的向前移动,并且窗口的大小是可变的)

GBN一个分组的发送格式是 Base(1Byte) + seq(1Byte) + data(max 1024Byte)

GBN协议的传送流程是: 从上层应用层获得到一个完整的数据报,将这个数据报进行拆分(一个GBN数据帧最大传输的数据大小限制为1024B,因为在以太网中,数据帧的MTU为1500字节,所以UDP数据报的数据部分应小于1472字节(除去IP头部20字节与UDP头的8字节)),如果发送方的滑动窗口中,如果窗口内已经被发送但未收到确认的分组数目未达到窗口长度,就将窗口剩余的分组全部用来发送新构造好的数据,剩余未能发送的数据进行缓存。发送完窗口大小的数据分组后,开始等待接收从接收方发来的确定信息(ACK),GBN协议采取了累积确认,当发送方收到一个对分组n的ACK的时候,即表明接收方对于分组n以及分组n之前的分组全部都收到了。对于已经确认的分组,就将窗口滑动到未确认的分组位置(窗口又有空闲位置,可以发送剩余分组了),对于未确认的分组,如果计时器超时,就需要重新发送,直到收到接收方的ACK为止。
对于超时的触发,GBN协议会将当前所有已发送但未被确认的分组重传,即如果当前窗口内都是已发送但未被确认的分组,一旦定时器发现窗口内的第一个分组超时,则窗口内所有分组都要被重传。每次当发送方收到一个ACK的时候,定时器都会被重置。
接收方只需要按序接收分组,对于比当前分组序号还要大的分组则直接丢弃。假设接收方正在等待接收分组n,而分组n+1却已经到达了,于是,分组n+1被直接丢弃,所以发送方并不会出现在连续发送分组n,分组n+1之后,而分组n+1的ACK却比分组n的ACK更早到达发送方的情况。

实现:

发送方:

首先定义窗口大小,起始 base 的值, 窗口采用链表的数据结构存储
private int WindowSize = 16;
private long base = 0;
进入一个循环,循环结束条件是所有需要传送的数据都已经发送完成,并且窗口中的分组都已经全部确认。
在这个循环中,如果窗口内有空余,就开始发送分组,直到窗口被占满,计时器开始计时,之后进入接收ACK的状态,收到ACK之后,更新滑动窗口的位置,之后如果计时器超时,就将窗口内所有的分组全部重发一次。之后开始下一次循环。

接收方:

不需要有缓存,只需要记录一个seq值,每成功接收一个数据帧,seq+1,开始循环顺序接收数据帧,对于seq不是目标值得数据帧直接丢弃,如果是符合要求的数据帧,就给发送方发送一个ACK=seq的确认数据帧,直到发送方没有数据传来为止。
GBN的实现就完成了。

SR协议的原理与实现:

SR协议的原理:

SR协议是在GBN协议的基础上进行的改进。
对于SR协议来说,发送方需要做到:
为每一个已发送但未被确认的分组都需要设置一个定时器,当定时器超时的时候只发送它对应的分组。
当发送方收到ACK的时候,如果是窗口内的第一个分组,则窗口需要一直移动到已发送但未未确认的分组序号。
对于接收方,需要设置一个窗口大小的缓存,即使是乱序到达的数据帧也进行缓存,并发送相应序号的ACK, 并及时更新窗口的位置,窗口的更新原则同发送方。

SR协议实现:

发送方:

在GBN发送方的基础上,增加一个基于链表数据结构的计时器,对每一个未被确认的分组进行计时。在每次判断是否超时时,需要对链表中所有的计时进行判断,与GBN重传不同的是,SR只对超时的那一个分组进行重传。

发送方完整代码见gitbub项目中 SR.java中的void send(byte[] content) 函数

接收方:

需要增加一个同发送方的对分组的缓存,用于缓存乱序到达的分组,同样使用链表数据结构。
List datagramBuffer = new LinkedList<>();
首先进入一个循环, 一次循环需要进行如下工作:
接收分组,将分组的数据缓存到datagramBuffer对应的位置(因为到达的数据可能是乱序的)
然后发送数据分组对应seq的ACK,告知发送方自己已经成功接收。 之后更新滑动窗口的位置,更新的规则同发送方一样。之后进行下一次循环。
直到发送方没有新的数据传来,超过接收方设定的最大时间,就结束循环,将接收到的数据拼接成一个完整的Byte数组,传给应用层。

接收方的完整代码见github项目中 SR.java中的 ByteArrayOutputStream receive() 函数

SR协议的实现就完成了。

双向传输的实现:

发送方发送数据需要占用一个固定的端口,而接收方也需要一个固定的端口来向发送方发送 ACK,所以就可以封装一个完整的协议类,类似于TCP的有连接传输一样,发送方和接收方之间在两个固定的ip和端口之间进行数据的传输,直到双方的传输结束。发送方在使用send()函数进行发送时,也可以同时使用receive()函数进行接收,两个过程并不冲突,可以同时进行。如果要同时收发,就需要同时开一个发送线程和一个接收线程,两个线程独立运行,没有冲突,这样就可以实现双向数据传输了。
所以我构造了一个SR class,其中包含的成员变量有:

private InetAddress host;
private int targetPort, ownPort;
private int WindowSize = 16;
private final int sendMaxTime = 2, receiveMaxTime = 4; // max time for one datagram
private long base = 0;
private final int virtualLossRemainder = 17; // this value is used to simulate the loss of the datagram as a remainder

包含的函数有两个:

void send(byte[] content) // 负责数据的发送
ByteArrayOutputStream receive()  // 负责数据的接收
private ByteArrayOutputStream getBytes(List<ByteArrayOutputStream> buffer, long max) //负责将接收到的数据分组拼接成一个完整的数据报
private boolean checkWindow(List<Integer> timers) 负责判断当前的窗口是否可以移动

详细的代码见github项目中SR.java

在Client 主函数中先使用SR协议发送一张图片, 在Server 主函数中使用SR协议接收这张图片,并保存。然后向Client发送另一张图片, Client由发送变成接收。
这有就可以实现双向文件的发送和接收了。
详细的代码见github项目中 Client.java 中 main函数和Server.java中的main函数

模拟丢包

在接收端,设立一个计数变量count, 然后每次收到数据帧就加一,如果count 对一个数取余=0就不发送ACK,模拟这一分组丢失的情况,然后测试发送方会不会重新发送丢失的分组。
这一部分的代码实现详见github项目中 SR.java中 receive中 count这个变量。

2018-06-08 14:40:37 qq_38505990 阅读数 114701

在计算机网络中,可靠的数据传输,是一个较为重要的问题,最近在看书(Computer Networking A Top-Down Approach),发现 rdt(Reliable Data Transfer) 大概经历了这样的变化。

这里写图片描述这里写图片描述
上图是两个主机相应进程之间的通信过程,左边是发送端,右边是接收端


rdt 1.0

在 1.0 版本中,我们将数据的传输信道理想化,视为完全可靠,不丢包,不损失bit ,在这样的情况下,发送端发送数据,接收端直接接收,并不考虑丢包,超时这些问题,下图是对应FSM(状态图)
rdt1.0
该协议中,都是直接发送,直接接收。


rdt2.0

果然,大家应该都意识到了,怎么可能这么理想化呢,要是传输通道完全可靠,我们讨论的意义何在呢?
在 rdt2.0 中,我们将传输通道视为有可能发生比特错误

有可能发生比特错误,这就是说,数据在传输中不会发生丢包的现象,但是会存在一部分比特错误的情况,于是我们引入:

差错检测:使用检验和,换句话讲,就是检验发过来的包有没有错误
接收方的反馈:接收方返回 NAK 或者 ACK ,分别对应数据错误和数据正确,这个也可以理解,总要告诉发送端,你发过来的是对还是错

rdt2.0
上图中的corrupt ,在字典里面是 “腐烂,腐化” 的意思,在这里可以理解成包出错。

很容易理解,发送端发出数据,并等待接收端反馈,如果返回 NAK ,表示数据出错,重新发送数据,至于接收端怎么检验数据,不用说,当然是使用检验和啦。


rdt2.1

经过大家思考,终于发现了 rdt2.0 的致命缺陷,原来接收端返回的值也可能会出错啊,万一NAK出错变成ACK了呢

于是诞生了 rdt2.1 ,该协议在 2.0 基础上增加了一个序号值(在这里,该序号在当前协议中只使用 0 和1 ,交替排列),这样一来,发送端和接收端都有了两种序号状态, 0 和 1 。
rdt2.1_sender
rdt2.1_receiver
我们来用自己的语言,组织一下上面的逻辑:
发送端在 0 序号时发送数据包,接收端此时期待 0 序号的数据包,如果数据发送时发生 bit 受损,此时接收端直接通过检验和发现错误,并返回 NAK ,发送端接到 NAK 的返回值,然后重新发送 0 序号数据包。(但是注意,这完全和 rdt2.0 没有任何分别,这是一种理想的状态!!!)

更错误的状况是,接收端成功接收,但是返回 ACK的时候发生了比特翻转,变成了 NCK ,这才是我们讨论的重点!!接下来,我需要画一张图,来理清楚当返回错误的时候,怎么通过序号来判断并重传数据。
rdt2.1编号重传检测
这样就解决了 NAK , ACK 返回值有可能出错的问题。


rdt2.2

由于相关开发人员的吹毛求疵,他们觉得需要返回 NAK , ACK 两种状态可能太麻烦了,就将其全部改为ACK 只是返回的时候顺便返回序号。
这里写图片描述
这里写图片描述
可以看到,接收端收到包,不管正确与否,都返回 ACK ,同时附上序号,这个序号嘞,就是数据包发送过来时的序号。另外的参照上图,相信同学们都能有所收获。


rdt3.0

可以说,在处理数据出错方面,上面的协议都做得很好了,但是,我们忽略了一个很大的问题,万一数据不是出现错误,而是直接丢失了呢!!这就是我们俗称的丢包了,于是,我们的 rdt3.0 千呼万唤始出来了。

所以在这里,我们假设的是最贴近真实的情况,数据传输通道发送和返回的过程中不仅会出错,而且还会丢包!

因此,我们引入一个新的机制——超时重传。先不考虑数据出错与否,数据发送出去,会有两种丢包可能:1.发送出去的时候丢失,接收端并未收到 。2.接收端收到了,但是在反馈 ACK 的时候,数据包丢失。在这两种情况下,发送端都是什么反馈都没有收到!!,那问题就简单了,我们设置一个时间间隔,超过时间没有收到,重新发送数据即可。(事实上还有很多问题,比如时间间隔多少合适,这里暂且不管)
这里写图片描述
上图是 rdt3.0 发送方的 FSM 图,就拿右上角的状态举例,此时发送端等待接收方返回的带有“0”序号的 ACK ,它有三种行为:

  • 第一种,过程中未丢包,但是数据比特出错或者不符合序号,和我们讨论过的 rdt2.2 差不多,那么此时就没有任何动作,毫无作为就好了,等到时间间隔一到,当做超时处理,重发数据。
  • 第二种,是真正的丢包了,所以时间一到,重新发送。
  • 第三种最理想,啥事没有,一切正常,跳到下一个状态,等待发送下一个包。

上面我加粗了一个不符合序号,细心的读者可能发现了,的确,在这里又是大有文章。

这里的不符合序号,与期待的序号不符,有两种情况:

  1. 接收端反馈过程中,代表序号的那个 bit 错误,进行了翻转——这就和 rdt2.2 中一样
  2. 我们上面引入了超时机制,但是有一种情形,万一我发出去的数据包并没有丢失,只是它跑的太慢而已呢??那么时间一到,发送端误以为丢包,重新发了一遍咋办??这就造成,接收端才收到你晚来的数据 0 号,还给你个 0 ,这时候你重传的 0 号包接着又到了,接收端又给你一个0 ,作为发送端,我会先后收到两个 0 ,就注定后面一个 0 会被期待 1 号的状态捕捉,这时发送端启动第一种处理方式——不作为,啥都不做。

    这里写图片描述
    上面便是示意图。


到此为止, rdt 3.0 已经被认为是一个较为完美的可靠传输协议了,但是还有着种种的不足,比如:

  • 效率太慢,由于停等方式的存在,一个包没处理好,发送端会一直等着。
  • 超时机制的时间间隔怎么确定?长了不行,太慢,短了么,又会经常有重复发包的情况。
  • …….
  • …….

    这些我将会在后续的博客上阐述,敬请期待吧~~

2017-10-10 12:33:37 Q3838418 阅读数 2199

一、首先,什么是可靠的数据传输?

不错(没有比特差错),不丢(丢包),不乱(按序到达)


二、然后一步步从0来构建这个可靠数据传输协议,看看他是怎么形成的。


三、构建前的约定:

1.用rdt表示可靠数据传输协议。

2.因为这里讨论的理论适用于一般的计算机网络,而不只是传输层,所以采用名词“分组”而不是传输层的“报文段”。

3.用“有限状态机”(FSM)来描述接受方和发送方的图。(有限状态机:即表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型,简单理解为一种画图方法)


四、开始构建

1.rdt1.0版本(假设底层信道是完全可靠的,底层是不丢不错不乱的

这种情况最简单,也是最理想的。那么直接拿着数据往下传或者往上传就好啦。有限状态机描述如下:

原英文版:

中文版:

2.rdt2.0版本(底层信道不再完全可靠,出现比特差错/受损)

*那么对于受损的分组,将要进行重传。基于这样重传机制的可靠数据传输协议称为自动重传请求(ARQ)协 议。

*ARQ协议中还需要另外三种协议功能来处理比特差错的情况:

1.差错检测。简单来说,就是需要一种机制使接收方能检测到出现了差错。类似UDP校验和,这种机制 需要额外的比特,这些额外的比特放在rdt2.0数据分组的分组校验和字段中。

2.接收方反馈。接收方得告诉发送方,他是否接受到了正确分组。rdt2.0中接受到正确的就发ACK分组, 错误的就发NAK分组,理论上只需要一个比特1表示ACK,0表示NAK.

3.重传。接到NAK重传该分组。

*有限状态机(FSM)如下(英文不明白可以对比rdt1.0中英文):

*像这种接收到ACK才能发生事件。rdt.0这样的协议也称为停等协议。

3.rdt2.1(rdt2.0中存在问题,如果ACK/NAK分组损坏了怎么办?)

*解决方法是收到损坏的ACK/NAK分组那么进行重传。

*但是!不能简单重传,那会造成冗余分组,接受方将不知道这到底是新发的还是上一个的重传!

*那么怎么解决这个问题?

一个简单方法(几乎所有现有的数据传输协议中,包括TCP都采用的这个)是在分组中添加一新字段, 让发送对分组编号。接受方根据编号就知道这是新分组还是重传了。

rdt2.1这种停等协议,加入0,1即可。一次发带0的一次发带1,以此往复,以此区分上一次和这一次。

*有限状态机(FSM)如下:

4.rdt2.2(无NAK消息协议)

*我们真的需要ACK和NAK两种消息吗?

不需要。ACK一种就够了。

*如何做到?

在ACK消息中加入最后一次正确接收的序列号

*原理

因为正常情况这次的发送分组序号和上次相反,上次是0这次则会是1.

如果接受成功,那么发送方接收到的ACK将与上一次序号不同。

如果接收失败,那么发送方接收到的ACK将会和上次序号一样。这样就触发重传。

*FSM(有限状态机)如下

5.rdt3.0(底层是 有比特差错  并且 会丢包 的信道)

rdt2.2基础上已经解决比特差错,实际也可以解决发生丢包后如何处理。那么问题的关键就是如何检查丢包。

方法: 发送方等待”合理”的时间内,用倒计时定时器,

如果没收到ACK,重传

如果分组或ACK只是延迟而不是丢了那么 重传会产生重复,序号机制能处理(rdt2.2已解决)

FSM(有限状态机):

*因为分组序号在0 1 之间交替,因此rdt3.0有时也被称为比特交替协议。

*至此,我们得到了一个可靠数据传输协议!

五、后续

1.rdt3.0是一个功能正确的协议,但是因为它是一个停等协议,性能非常糟糕。

2.解决办法是打破停等协议。不使用停等方式运行,运行发送方发送多个分组而无需等待确认

许多发送的分组可以被看成填充到一条流水线中,故这种技术被称为流水线机制

3.流水线技术对可靠数据传输协议可带来如下影响:

--更大的序列号范围

--发送方和接收方需要更大空间缓存分组

--解决流水线的差错恢复有两种基本方法:回退N步(GBN,滑动窗口协议的一种实现)和选择重传(SR)

4.滑动窗口协议

窗口:

  • 允许使用的序列号范围
  • 窗口尺寸为N:最多有N个等待确认的消息 
    滑动窗口

  • 随着协议的运行,窗口在序列号空间内向前滑动 
    滑动窗口协议有GBN和SR

4.GBN(回退N步协议),发送方看到的序号(注意!这是一次性发送的窗口情况,全结束后,下一波继续会有一张重新的窗口情况,比如下面这个表明一次性最多发56个):

*采用的累积确认的机制,如果收到的是ACK(N),表示确认到N的序列号分组均已被正确接收

*为空中的分组设置计时器(丢包问题)

*超时Timeout(N)事件:重传序列号大于等于N,还未收到ACK的所有分组。(这里潜在有资源浪费问 题)

2018-05-20 11:22:54 springtostring 阅读数 11718

计算机网络的设计基本方案是复杂化,多功能化应用层,运输层的协议设计,从而使得网络层,链路层,物理层变得相对简单,网络搭建的物质条件变得简单。由于网络层较为简单,采用了无连接的协议,在不可靠信道上传输,导致数据传输是不可靠的。为了保证数据传输的可靠性,我们选择在运输层采用复杂的rdt(可靠数据传输协议),以完成网络的可靠性。

原理图如下所示:

rdt协议经历了rdt1.0,rdt2.0,rdt2.1,rdt2.2,rdt3.0.一步步完善,使得网络得到很好的安全性稳定性。

rdt1.0是基于理想情况下的协议,假设所有信道都是可靠的,没有比特位的翻转,没有数据包的丢失与超时,所以rdt1.0的传输功能就是 发送方发送数据,接收方接受数据。

rdt2.0在rdt1.0的基础上解决了比特位翻转的问题,这里的比特位防撞发生在运输层下面的不可信信道中数据包中的1可能会变0,0可能会变成1。rdt2.0增加了3种新机制:1.错误检验 2.接收者反馈接受信息(ACK,NAK)3.重传机制。在运输层对应用层的数据进行打包处理时,新增checksum(校验和),从而接收端可以对其数据包进行检验,如果正确,返回ACK,发送者继续发送下一个数据包;如果不正确,返回NAK,发送者重传数据。

但是rdt2.0有着一个致命的缺点,只考虑了发送方到接收方的数据传输,如果反馈信息ACK,NAK传输时发生比特位翻转会出现什么情况?如果ACK发生翻转,那么发送方会再次重复的发送相同的数据包;如果NAK发生翻转,那么发送方会认为数据传输情况很好,但是接收方却已经收到了一个错误的数据包。

 

由此rdt2.1应运而生,在rdt2.0的基础之上,发送方在打包数据包时添加了0或者1编号,同样ACK,NAK字段上也添加了0,1字段,表示0.1号字段的确认或者否定。发送方就有了2种状态发送0号数据包,1号数据包,接收方也有了2种状态等待0号数据包和等待1号数据包。现在假设情景发送方向接收方发送0号数据包,如果接收方接收到0号数据包,返回ACK,但是ACK出现翻转,接收方处于等待1号数据状态,发送方重复发送0号数据,接收方会拒绝0号数据,避免重复。如果接收方接收到0号数据包出现错误,返回NAK,但是NAK出现翻转,接收方处于等待0号数据状态,发送方继续发送1号数据,接收方会拒绝1号数据,避免错序。

rdt2.2是在rdt2.1上的基础之上做了小小的改善,摒弃了NAK,只需采用ACK。我们在ACK的信息上加上了期望的顺序号,现在假设情景发送方向接收方发送0号数据包,如果接收方接收到0号数据包,返回(ACK,1),发送方接着发送1号数据包。如果接收方接收到0号数据包出现错误,返回(ACK,0),发送方重传0号数据包。

rdt2.2之前的版本都重在处理数据包的比特位翻转情况,却没有考虑到数据包在传输过程中出现的数据包丢失问题,这样数据包丢失会使得网络处于拥塞状态。

rdt3.0在rdt2.2的基础之上处理了数据包丢失的情况,增加了计时器的机制,如果在RTT时间段内,发送方没有接收到反馈信息,那么发送方默认数据包已经丢失了,会自动重传。

rdt3.0性能分析:

rdt3.0 可以工作, 但是性能很差

ex: 1 Gbps 链路, 15 ms 传播延迟, 8000 bit数据报:

U sender: utilization – 发送者忙于发送的时间占比

每30 msec发送 1KB pkt -> 33kB/sec (1 Gbps 链路)

这是一个网络协议严重影响链路资源利用的一个例子!

主要原因是在RTT时间段内,网络处于空闲状态,而RTT时间段比较长,使得利用率十分的低。

在此基础上采用流水线协议来改进rdt3.0

允许发送者发送多个, “在途(in-flight)”, 等待确认的数据报
顺序号的范围必须扩大
Sender /receiver必须使用缓冲区

主要有两类流水线协议: go-Back-N, selective repeat。

大致描述如下:

 go-Back-N(回退N重传协议):

1.发送者在流水线中最多有 N 个未确认的数据报。

2.接收者仅发送累计的确认 ,如果中间有数据报缺失,就不予以确认。

3.发送者对最久未确认的数据报进行计时,如果计时器到点, 重传所有未确认的数据报。

4.发送窗口大于1,接受窗口等于1(也就意味着如果某一个报文段出现错误,那么接受窗口会停留再次,之后收到的数据将会被丢弃)

selective repeat(选择重传协议):

1.发送者在流水线中最多有 N 个未确认的数据报。
2.接收者对单个数据报进行确认。

3.发送者对每一个未确认的数据报进行计时,如果计时器到点, 仅重传该个未确认的数据报。

4.发送窗口大于1,接受窗口大于1(意味着可以缓存出错位置之后的报文段),最好是两者相同


2018-08-18 10:44:55 lyf_ldh 阅读数 3917

计算机网络学习的核心内容就是网络协议的学习。网络协议是为计算机网络中进行数据交换而建立的规则、标准或者说是约定的集合。计算机网络协议同我们的语言一样,多种多样。

为了给网络协议的设计提供一个结构,网络设计者以分层的方式组织协议。

一个协议层能够用软件、硬件或者两者的结合来实现。比如HTTP和SMTP这样的应用层协议几乎总是在端系统中用软件实现的,传输层协议也是如此。因为物理层和数据链路层负责处理跨越特定链路的通信,它们通常是实现在与给定的链路相联系的网络接口卡(比如以网络或WIFI接口卡)中。网络层通常是硬件和软件实现的混合体。

1.网络层次划分

将所有的协议综合起来,各个层次的所有协议被称为协议栈。因特网的协议栈由5个层次组成:物理层、链路层、网络层、传输层和应用层。这个划分方法称为TCP/IP五层协议。除此之外,还有OSI七层模型和TCP/IP四层协议。它们之间的对应关系如下:

网络层次

当然比较常用的是TCP/IP五层协议。

1.1 应用层

应用层是网络应用程序以及它们的应用层协议存留的地方。因特网应用层包括许多协议,例如HTTP(Web应用的主要协议)、SMTP(邮件传输)和FTP(文件传送)等。再比如我们每天都在使用的DNS域名系统。

应用层协议分布在多个端系统上,一个端系统中的应用程序使用协议与另外一个端系统中的应用程序交换信息的分组。
我们把位于应用层的信息分组称为报文

1.2 传输层

因特网的传输层在应用程序端点之间传送应用层报文。在因特网中,有TCP和UDP两个传输层协议。

TCP向它的应用程序提供了面向连接的服务,这种服务包括了应用层报文向目的地的确保传递和流量控制。TCP也将长报文划分成短报文,并提供拥塞控制机制,因此,当网络拥塞时,发送方可以抑制其传输速率。

UDP协议向它的应用程序提供无连接服务。这是一种不提供不必要服务的服务,没有可靠性,没有流量控制,也没有拥塞控制。

我们把传输层分组称为报文段

1.3 网络层

因特网的网络层负责将称为数据报的网络层分组从一台主机移动到另一台主机。在一台源主机中的因特网传输层协议(TCP或者UDP)向网络层递交传输层报文段和目的地址。

网络层包括著名的IP协议,该协议定义了在数据报中的各个字段以及端系统和路由器如果作用于这些字段。网络层也包括决定路由的路由选择协议,它使得数据报根据该路由从源传输到目的地。

1.4 链路层

网络层通过源和目的地之间的一系列路由器路由数据报,为了将分组从一个结点移动到路径的下一个结点,网络层必须依靠链路层的服务。特别是在每个结点,网络层将数据报下传给链路层,链路层沿着路径将数据报传递给下一个结点,在下一个结点,链路层将数据报上传给网络层。

由链路层提供的服务取决于应用于该链路的特定的链路层协议,比如我们常见的以太网,WIFI等。

因为数据报从源到目的地传送通常要经过几条链路,一个数据报可能被沿途不同链路上的不同链路层协议处理。例如,一个数据报可能被一段链路上的以太网和下一段链路上的PPP所处理。网络层将受到来自每个不同链路的链路层协议的服务。

我们把链路层分组称为

1.5 物理层

链路层的任务是将整个帧从一个网络元素移动到邻近的网络元素,而物理层的任务是将该帧中的一个一个比特从一个结点移动到下一个结点。物理层的协议是和链路相关的,并且进一步与该链路的实际传输媒体相关。比如,以太网具有许多物理层协议:一个是关于双绞铜线的,另一个是关于同轴电缆的,还有是关于光纤的等等。

2.封装

封装

上图显示了这样一条物理路径:数据从发送端系统的协议栈向下,经过链路层交换机和路由器的协议栈,进而向上到达接收端系统的协议栈。

我们需要知道的是,路由器和链路层交换机都是分组交换机,它们不实现协议栈中的所有层次,链路层交换机实现了第一层和第二层;路由器实现了第一层到第三层。这意味着,路由器能够实现IP协议(即第三层协议),而链路层交换机则不能,于是链路层交换机不能识别IP地址,但是能够识别第二层地址,比如MAC地址。

但是,因特网中的所有主机都实现了所有5个层次的协议。


上图的过程也说明了一个重要的概念:封装

在发送主机端,一个应用层报文被传送给传输层。传输层收到报文之后,在报文上附上附加信息,即所谓的传输层首部信息,该首部信息将被接收端的传输层使用。应用层报文和传输层首部信息一起构成了传输层报文段,传输层报文段因此封装了应用层报文。

传输层则向网络层传递该报文段,网络层增加了网络层首部信息,比如源和目的端系统的地址等,由此产生了网络层数据报

该数据报接下来被传递给链路层,链路层增加它自己的链路层首部信息,创建了链路层帧

所以,我们看到在每一层,一个分组都具有两种类型的字段:首部字段和有效载荷字段。而有效载荷即来自于上一层的分组。

其实说白了,发送端就是对应用层数据一层一层加头的过程,到接收端后,接收端再一层一层去掉头部信息,然后交给对应的应用程序