数据链路层概述
从数据链路层来看,主机 H1 到 H2 的通信可以看成是在四段不同的链路上的通信组成的,所谓链路就是从一个节点到相邻节点的一段物理线路,中间没有任何其他的交换节点。要在链路上传输数据,仅有链路还不够,还需要一些通信协议来控制这些数据的传输。若把实现这些协议的硬件和软件加到链路上,就构成了数据链路。
在数据链路层上传输的数据包又称为帧
,也就是说数据链路层以帧为单位传输和处理数据。
接下来我们介绍数据链路层的三个重要问题,他们是封装成帧
、透明传输
、差错检测
。
封装成帧
所谓封装成帧,就是指数据链路层给上层交付下来的协议数据单元添加帧头和帧尾,使之成为帧,例如下图所示:
在帧头和帧尾中包含有重要的控制信息。
接收方的数据链路层如何从物理层交付的比特流中提取出一个个的帧呢?实际上帧头和帧尾的作用之一就是帧定界。若忽略与帧定界无关的控制信息,帧可以如下表示:
帧定界一般用特殊的控制字段:
SOH
:帧开始符,16进制表示为01H
EOT
:帧结束符,16进制表示为04H
不过要注意,不是所有的帧都使用SOH
和EOF
。
假设发送端由于故障,某一个帧发送到一半停止,然后重新发送:
由于帧定界符的存在,第一个SOH没有匹配的EOT,接收方就知道这不是一个完整的帧,于是把它丢弃。第二次再收到一个同时带有SOH和EOF的帧,才算收到一个完整的帧。
现在考虑这样一个问题:如果一个分组的数据段太短,那么首部和尾部的占比就很大,传输效率低;如果一个分组的数据部分太长,此时就削弱了分组的优点。
因此,每一种数据链路层协议都规定了能传输的数据部分上限,及最大传送单元MTU 。
一般来说,MTU
的默认值是1500 byte
,也就是说网络层交给数据链路层的数据部分,不能超过1500 byte
。
透明传输
接下来我们介绍透明传输的问题。透明传输是指数据链路层对上层交付的传输数据并没有任何限制,就好像数据链路层不存在一样。
我们来举例说明。这是发送方数据链路层收到其上层交付的协议数据单元,给其添加帧头SOH
和帧尾EOT
,使其成为帧:
但是我们的数据部分中也存在和EOT
一样的数据段,那么就会发送以下情况:
数据段中的EOT被错误的认为是一个帧尾,此时把前面一段误以为是一个帧,后面的的数据因为缺少SOH而被丢弃。
也就是说,数据链路层对上层交付的协议数据单元有限制,其内容不能包含帧定界符。那么此时数据链路层就不能算作透明传输,因为网络层传输的数据会受到数据链路层的影响,不能传输SOH,EOT这样的字段,不能当作数据链路层不存在。
实际上,各种数据链路层协议一定会想办法来解决这个问题。
规则如下:
在发送帧之前对帧的数据部分进行扫描,每出现一个帧定界符EOT或SOH,就在其前面插入一个转义字符ESC
接收方数据链路层在物理层交付的比特流中提取帧,遇到第一个帧定界符SOH
时,认为这是帧的开始。当遇到转移字符ESC
时,就知道其后面的一字节内容虽然是SOH
或者EOT
,但它是数据而不是定界符。剔除转移字符后,将其后面的内容作为数据继续提取。
大家再来思考一下这种情况。在上层交付给数据链路层的协议数据单元中,既包含了帧定界符,又包含了转义字符ESC
:
这应该怎么处理呢?方法仍然是在发送帧之前对帧的数据部分进行扫描,每出现一个帧定界符或转义字符就在其前面插入一个转义字符:
当接收方遇到ESCESC这样的数据后,就知道第一个ESC是转义字符,第二个ESC是数据,于是剔除第一个ESC,保留第二个ESC。
需要说明的是,转义字符是一种特殊的控制字符,其长度为一个字节,十进制值为27,而并不是 ESC这三个字符。
以上我们讲述的方式叫做字节填充,在PPP协议中还存在一中比特填充的方式来进行透明传输,这个在PPP协议的博客中讲解。
差错检测
再来看差错检测,发送方将封装好的帧通过物理层发送到传输媒体。帧在传输过程中遭遇干扰后,可能会出现误码,也就是比特 0 可能变成了比特 1,反之亦然。
在一段时间内,传输错误的比特占所传输比特总数的比率,称为误码率。
但是接收方主机如何判断帧在传输过程中是否出现了误码呢?
这可以通过检错码
来发现。发送方在发送帧之前基于待发送的数据和检错算法计算出检错码,并将其封装在帧尾。接收方主机收到帧后,通过检错码和检错算法就可以判断出帧在传输过程中是否出现了误码。
在数据链路层传输的帧中,广泛使用了循环冗余校验 CRC
的检错技术。
假定发送端发送的原始数据为k
个比特,对原始数据进行CRC
运算,产生了n
位冗余码FCS
,把n
位冗余码FCS
放入帧的末尾一起发送出去。
那么我们现在就来讲解一下这个冗余码FCS
是如何计算的:
- 在原始
k
位数据后面加n
个0
- 用指定的
n + 1
位除数p
,对这个k + n
位的数据段做模2除法 - 最后得到的
n
位除数就是冗余码FCS
,用冗余码FCS
替换最后的n
位0
假设我们现在的原始数据为101001
,约定的除数p
为1101
:
除数p
为4位数,那么n
就是4 - 1 = 3位,因此在101001
后面添上3位0:
现在就可以开始进行模2除法了:
所谓模2除法,就是每次进行相除操作时,上下按位异或,比如以上式子中1010
和1101
按位异或就是0111
,在后面补一位0就是1110
。以此类推,一直计算下去:
由于我们的除数p是n + 1位,所以最后的余数一定是小于等于n位的,如果不够n位就在前面补0,补到n位。然后把这n位除数替换掉原数据中的n位0,得到101001 001。
101001 001这一段数据中,101001是原始的数据, 001就是冗余码FCS。
,一开始我们拿p除以101001 000,余数为001。我们把001补上去后,数据变成了101001 001,那么p除以101001 001就应该是0。因此如果接收端用p除以k + n位数据等于0,就说明数据没有出问题,是正常的。但是如果结构非0,说明有比特位出现了差错,那么接收端就可以知道传输出问题,进行后续操作了。
要注意的是,这个除数p是一开始双方就约定好的,因此双方都是知道拿p去除以这个数据段。