便于表达和理解,下面的例子大多基于连接两台电脑的连接为具体例子
物理层把两台电脑(当然可以是多台)通过各种物理线路和硬件设施将它们连接了起来,现在两台电脑能互相发送和接收信号了,但也只是能发送和接收信号而已,对于接收者,通过调制解调器之后也就只能得到一堆01数据串,没有其它信息,无从解析。所以需要两台电脑之间形成一种约定,这个约定规定了每次发送的数据的格式等,有了这样的约定两者才能实现有意义的数据传输,来负责管理这个约定的就是链路层
举例来说就像隔得很远的两个人要互相通信,现在给了他们两个人一人一个手电,他们可以通过手电的闪烁来传递信息,手电就是物理层的内容将他们”连接”了起来,但是如果只有手电闪烁两人也无法进行有效的通信,现在两人约定一个人要开始讲话时就让手电常亮5秒,然后中间用摩斯电码或者其它方法传递信息,表示讲话完毕就常亮手电7秒,这样双方才能进行有意义的通信,而”开始讲话时…7秒”的这种规定就是链路层要做的工作
概念辨析
链路是物理上的将两台电脑连接起来的一条物理线路,而数据链路是在此基础上增加一些通信协议,这些协议具体实现到硬件和软件上,现在物理层和链路层的协议大多实现在网卡(网络适配器)上
点对点信道的数据链路层
链路层要解决的问题:1.封装成帧 2.透明传输 3.差错检测
封装成帧
这个问题比较容易想到,如果传递的数据没有边界划分那接收者根本不知道改从何处开始解析,所以很自然地就需要对数据进行一个简单的封装,封装的方法就是在数据部分的首尾加上特殊的数据其实也就是特定的01串,至于用什么样的界定符是标准需要讨论的问题,一个这样加上头部和尾部的01串就是一个*帧(Fram)*。当然头部和尾部还可以加上一些控制信息这些是具体的实现细节。接收端只有看到SOH和EOT时才会认为这是一个完整的帧,否则将丢弃接收的数据
帧开始符 帧结束符
| |
---------------------------------------
| SOH | 封装的数据部分 | EOT |
---------------------------------------
透明传输
上面的问题中要规定特殊的界定符,但是无论它取什么,都无法保证后面的数据部分不会有跟其一样的01串出现,如果不采取某种措施那接收端就会错误地将一个帧给切分掉。
这里解释一下透明传输,所谓透明是对使用者来说的,就像这里使用者不用知道界定符选了什么,他只管把自己的数据打包成上面的数据部分,不用担心自己的数据中会出现跟界定符一样的01串,因为当使用者把数据给到链路层的时候链路层会来处理这个问题,所以这个传输问题对使用者来说就像透明的一样,不存在
现在回到链路层,如何解决这个问题,其实思路就跟C语言的字符转义一样,跟界定符重复了那就把它变成不一样的东西,接收者再把它翻译回去即可。具体做法就是发送端的链路层在数据部分出现跟界定符一样的地方的前面再插个特殊的”转义符(ESC)”,接收端看到这个转义符就不会把后面的01串当作界定符,并且在将数据传给自己的上层使用者之前把这个转义符给删掉。这种方法称为字符填充
差错检测
解决上面两个问题可以进行通信了,但现实中通信的链路并不完美,传输过程中可能会出现某些数据位的错误即某些位0变1,1变0,此时需要链路层来检测出这些错误。
目前广泛使用的一种方式就是**循环冗余检验(CRC)**,其原理如下:
- 发送端会把数据分组,假设一组数据有n位,在后面添加k位额外的数据用以接收端校验,这多出来的k位就叫冗余码
- k位的冗余码可以这样得出:首先双方商定好一个除数P(位数为k+1位),然后在原始的数据后面加k位个0,用新的数据来对P做模2除(模2运算不会产生进位借位),得到的k位余数就是要加上的k位冗余码(FCS Frame Check Sequence)
- 接收方剥开帧之后取出数据部分对其同样进行模2除,如果得到的余数R不为0则说明传输过程发生了错误
比如传输的数据为M = 101001,头尾界定符为10010,选择除数P=1101,则这个帧的数据应该为:
10010 101001 001 10010
后面的001是这样得来的
110101
------------
1101 |101001000
1101
-------------
1110
1101
---------
0111
0000
---------
1110
1101
---------
0110
0000
--------
1100
1101
-----
001
可以看到就是先在101001后面加了3个0然后对1101进行模2除取的余数
当然也有可能出现了差错但是接收端对发生了差错的数据进行模2除得到的余数也为0,但这种概率非常的小,如果仅用CRC检验,链路层只能做到无差错的接受,即只要是接受的帧,就认为没有发生错误,无法提供可靠传输服务,因为这里还没有机制解决可能出现的1.帧丢失 2.帧重复 3.帧失序这几种传输差错。
这个服务现在一般由上层服务保证,但链路层也可以提供此服务,需要增加一些帧编号,确认,重传等机制
下面是具体的一个点对点链路层的协议
PPP(Point to Point Protocol)
从这个名字可以看出来,它大概就是用于两台机器连接的协议,书上说的是互联网用户接入ISP时使用的协议,这个协议用于串口线路,所以用一根双绞线直接连接两台电脑是看不到这个协议的,后面我会贴一个用Packet Tracer模拟出PPP协议的实验
作为链路层的协议,它肯定需要解决上面三个基础问题,另外一些其它要求可以参考RFC 1547
PPP协议由三个部分组成:
- 一个将IP数据报封装到串行数据链路的方法
- 一个用来建立,配置和测试数据链路的链路控制协议(LCP Link Control Protocol)
- 一套网络控制协议(NCP Network Control Protocol)
PPP协议的帧格式
字段意义
首先第一个字节是界定符0x7E,后面一个字节规定为0xff,再后面一个字节规定为0x03,这三个字节目前定死,不用改变。后面两个字节表示数据部分采用什么样的协议,如为0xc021则表示信息字段是LCP的数据,而如果为0x8021则表示NCP的控制数据。后面就是信息字段,长度可变,但不超过1500字节,后面就是两字节的FCS然后再是一字节的界定符0x7E,如图所示:字节或比特填充
当信息段出现跟0x7E一样的比特组合时就需要采取一些措施
参考RFC 1662的内容:
PPP协议支持同步和异步传输,简单地理解同步传输就是以帧为单位进行传输,异步传输就是以字符为单位进行传输
当采用异步传输时,转义字符选为0x7D,使用字节填充,当信息字段每出现一个0x7E,0x7D或者一个小于0x20(属于ASCII码的控制字符)的字符,就在这个字符之前添加一个0x7D,然后将这个字符与0x20做异或之后发送。接收方在进行FCS检查之前会将0x7D删除,并将其后面的字符与0x20异或转换.
而当采用同步传输时,数据是一帧一帧的,也就是一长串01串,由于界定符为0x7E表现为0111 1110,也就是说在中间部分不应该出现六个连续的1,这很简单只要发送端在每5个连续的1后面加一个0就行了,接收端每扫到5个连续的1就忽略掉后面的一个0,这样就能翻译回去了。
PPP协议的工作状态
大致如下:
两台电脑无连接->两台电脑有了物理连接->LCP链路->鉴别的LCP链路->NCP链路
双方建立好物理连接后开始发送LCP的数据包开始建立数据的链路和配置,包括链路的最大帧长,使用的鉴别协议等,协商完成后就建立了LCP链路。之后进入鉴别状态,这一状态只允许传输LCP数据包,两种鉴别协议为PAP和CHAP,鉴别完成则建立起一条鉴别的LCP链路.
之后网络层发送NCP的数据进行控制,如运行的是IP协议,则使用NCP中的IPCP协议进行控制,包括分配IP等工作
使用广播信道的链路层
下面是以局域网为例进行的广播信道的讨论
广播信道必须要解决信道共享的问题,在技术上主要有两种方法:
- 静态划分信道,如前面物理层中所提到的频分复用,时分复用,码分复用等方式,用户只要分配到了信道就不会与其他用户产生冲突,但代价较高,不适用于局域网
- 动态媒体接入,特点是信道并非固定分配给用户,由细分为以下两类:
- 随机接入:所有用户可以随机地发送信息,如果有多个用户同时发送信息则产生碰撞,这些用户都发送失败,这里就需要一个协议来解决碰撞发生之后的情况或者说解决这种模式下怎么保证信道有效的使用
- 受控接入:用户发送信息受到控制,不能随意发送,比如只有持有某个“令牌”的用户可以发送,然后此令牌在用户中流转。
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 2128099421@qq.com