1. 总体认识
如今TCP/IP协议簇已是计算机网络的主流协议框架,它是一个四层协议,依下往上分为网络接口层、网络层、传输层、应用层。有很多人将网络接口层分为物理层和数据链路层,因此也称为五层协议。物理层考虑的是如何连接不同主机的传输媒体设备,以便完成网络通信,主要是一些硬件的规范;数据链路层则是考虑在一个局域网内,如何将网络数据从一个主机传输到另一个主机。本文将从数据链路层开始,探索计算机网络基本原理。
数据链路层在五层协议中的位置如下图所示,我们只需关注它与网络层和物理层的交互。当网络层的IP数据包到达数据链路层时,会在这一层为IP数据包添加首部和尾部,封装成一个帧,它是这一层实现通信的协议数据单元。随后数据链路层会把帧交给物理层,由它实现最终硬件上的网络数据发送。当数据链路层收到物理层提供的帧时,若能通过检测则会去掉首部和尾部,提取出IP数据包上交给网络层。否则会直接丢弃检测有差错的帧。
数据链路层分为2种信道:一种是点对点信道,使用一对一的点对点通信方式;一种是广播信道,它使用一对多的广播信道方式。由于广播信道上存在很多主机,因此必须使用专用的共享信道协议来协调这些主机的数据发送。不管是何种信道,数据链路层都不需要考虑物理层如何实现比特传输的细节,也不需要考虑网络层如何进行路由转发,它只需要专注于这一层的主机通信既可。这也是计算机网络中最核心的设计思想:分层。
2. 三个问题
数据链路层的协议有很多,但不管是哪种协议。它们在设计时,都必须考虑以下3个问题:封装成帧、透明传输、差错检测,下面将分别讨论这3个问题。
通过上面的介绍,已经知道数据链路层会对网络层下发的IP数据包增加首部和尾部以达到封装成帧的目的。当一个最原始的数据从应用层一步一步下发到数据链路层时,其实已经携带了各层的一些控制信息,比如网络层会在头部增加源IP、目的IP。数据链路层也不例外,它会利用增加首部和尾部的机会,把这一层必要的控制消息放入首部和尾部。这样一个帧就形成了,帧长度是IP数据包的长度加上帧首部和帧尾部的长度,此时IP数据包将作为帧的数据部分发送至网络中。在一次传输过程中,真正的数据其实是数据部分,首部和尾部只是为了能够正确的使这个帧到达目的地,因此往往希望数据部分能够尽可能的较长,这样就可以携带更多的数据信息。但是数据部分也不能太长,网络层会对IP数据包的长度进行限制,使其在一个合适的范围,而这个范围则被称为最大传送单元MTU。现在你已经知道为什么需要增加首部和尾部,但马上又有一个新的问题出现。
当目的主机的数据链路层收到物理层上传的数据后,应该如何从中提取出IP数据包上交给网络层呢?显然有很多方式可以实现这个功能,比如设置2个固定的长度字段,分别表示首部和尾部所在的位置。还可以使用一个特定的标志符,只要第一次遇到这个符号,那么就说明后面的内容是数据部分。第二次再遇到这个符号,那么后面的内容就是尾部,当然这是在特殊符号只会出现2次的基础之上,而这正是透明传输要解决的问题。在这个功能实现后,我们还可以利用这个功能做一些校验。比如采用2个固定字段表示位置时,若第2个字段里的值为600,可是整个帧的长度只要500。这说明这个帧根本就没有发送完,是一个错误的帧。目的主机收到这样的帧时,将直接丢弃,因为这不是一个完整的帧。
透明传输在前面也提过,它要解决的问题是让标志首部和尾部的特殊符号仅出现一次,也称这2个特殊符号为帧定界符。最终会达到这样的效果,无论网络层下发什么样的IP数据包,都可以万无一失的插入帧中的数据部分,且不会出现帧的数据部分还有帧定界符。这个问题是一个概念性的问题,随着时间的推移你总会明白的。
差错检测是一个非常重要的问题,在真实的计算机网络中,每次传输都有可能出现差错,比如二进制数据由1变成0,或0变成1。实际的通信链路是无法完全保证目的主机接收的比特流与发送方发送的比特流完全一致,因此为了数据可靠性,必须存在差错检测功能,且只要差错检测不通过,这个帧将毫无条件的被丢弃。
差错检测分为2种情况,第一种是比特错误,就如上面提到的数据流中有1变成0的情况,这称为比特差错;第二种是传输差错,比如帧重复、帧丢失、帧失序,但是每个帧本身的数据内容则是正确的。帧重复就是发送方只发送了一个帧,但是接收方却收到了2个帧,帧丢失和帧失序的概念同帧重复类似。下面将分别讨论比特差错和传输差错。
3. 差错检测
比特差错的问题在于比特错误,因此只需要检测发送方的比特流与接收方的比特流是否相等既可。目前数据链路层广泛采用了循环冗余检验CRC来完成比特差错检测,它的基本原理是对数据进行计算,得到一个冗余码,学名是帧校验序列FCS。这个码将会添加在帧的尾部作为帧的一部分发送出去,接收方收到后根据FCS完成校验。具体例子如下,首先收发双方会事先商定一个长度为n+1的除数P,n是FCS的长度。现在假如数据M为101001,一共6位,那么会对数据进行一个乘法运算,用M乘以2的n次方,相当于在M后面加n个0。这样M就变成101001000,接着用101001000除以P,得到商为110101,余数001。这个余数正是我们需要的FSC,它将加在M的尾部使得M变成101001001,这就是最终发送出去的数据。接收方收到后,会用数据M(101001001)除以P,得到一个余数R。对于余数R,有两种情况。若R=0,说明这个帧的比特流是正确的,准备接收。若R!=0,说明这个帧存在比特错误,直接丢弃。流程图如下所示,通过CRC,可以保证数据链路层的比特流是可靠的,但是它依旧无法向网络层提供可靠传输,因为还存在传输差错。
传输差错导致即使CRC校验通过,也不能肯定传输成功。对于帧丢失和帧失序等问题,如果要解决的话我们必须在设计数据链路层时,还要增加一些规范。比如帧重复问题,可以在数据链路层的首部增加帧编号字段,如果接收方收到2个同样编号的帧,那说明这是有问题的。但是这个问题应该如何反馈呢,所以还需要确认机制。OSI针对这个问题的观点是必须在数据链路层保证可靠传输,一旦收到正确的帧就要理解回复确认,若未在规定时间内收到确认则需要重传。随着通信质量的大大提高,传输差错的情况已经较少见,如今的做法是采用区别对待的方式。对于通信质量较好的有线链路,不需要数据链路层向上提供可靠传输服务,可靠性的传输工作交由上层协议来完成。对于通信质量较差的无线传输链路,数据链路层使用确认和重传机制保证可靠性传输。