在我前几篇文章中,已经介绍了TCP/IP四层协议模型中的上三层协议,其中应用层负责完成实际的
业务需求,而传输层中的TCP协议负责数据在网络中传输的可靠性,网络层中的IP协议提供将报文
跨网络送到目标主机的能力,也就是在网络拓扑结构中进行路径选择,到了这里我们就可以提供了
将有效数据可靠的送到目的地的道路了,但是具体这条路怎么走,这就是我今天要介绍的下一层
——数据链路层,而数据链路层中负责完成“走路”功能的就是Mac帧协议了。
1. 知识铺垫
在上面的介绍中,TCP/IP四层协议模型中,TCP和IP协议就已经为将要传输的数据提供好一条可靠的道路到目标主机了,但是怎么去这是属于数据链路层的范畴了。
在IP协议中,我曾经说过IP协议提供将报文跨网络送到目标主机的能力,并且也介绍了路径选择的具体规则,我们再来看这一张图:
上面展示了数据从主机B到主机C的大致的一个路径选择,在认识IP协议之后,我们知道一个子网中是有很多个设备的,也就是说在主机B和路由器A所处的子网中大概率还有着其他设备,当数据在主机B的时候,主机B的IP协议通过路由表判断这个报文的目标子网不是该子网,那么就会将这个报文发送到该子网中的默认出口路由器中,这时报文的源IP地址会发生变化,这个时候这个报文就发生了跨网络的行为。
为什么这个报文要发送到路由器A,这是IP协议的功能,但是怎么到路由器A这是数据链路层的功能。
而IP协议中所提到的跨网络,这个网络就是一个子网,说得再具体些就是一个局域网,而现在在局域网中所使用到的具体技术叫做以太网,所以在认识数据链路层之前,我们应该还得认识一下以太网。
以太网
"以太网" 不是一种具体的网络, 而是一种技术标准; 既包含了数据链路层的内容, 也包含了一些物理层的内容.
例如: 规定了网络拓扑结构, 访问控制方式, 传输速率等;
例如以太网中的网线必须使用双绞线; 传输速率有10M, 100M, 1000M等;
以太网是当前应用最广泛的局域网技术; 和以太网并列的还有令牌环网, 无线LAN等;
在一个局域网中一般各个主机之间都是直连的,所以一个局域网中的草图可以表示为下图:
其中Mac + 字母表示各个主机的Mac地址,IP + 字母表示各个主机的IP地址
2. Mac帧协议
Mac帧协议格式
在有了上面的认识之后,我们清楚了数据链路层中主要的功能就是让一个局域网中的主机进行正常通信,而其中最主要的协议当属Mac协议,接下来我们来认识Mac帧协议的格式:
在我的上一篇介绍IP协议的文章中,就提到了Mac协议中报文携带的有效载荷一般最大值是1500,而在这里有效载荷还有最小值,一般不低于46,那有人就有问题了,如果低于46怎么办呢?此时Mac帧协议会对数据进行补充达到最小值以上。
在认识一个协议格式的时候都绕不顾两个问题:报头和有效载荷如何分离?如何向上交付?
在Mac帧协议中,我们发现该报文中报头部分(包括后面的CAC校验,这个字段不做介绍)是定长的,所以报头和有效载荷分离的问题可以解决。
而如何向上交付则是需要报头中的类型字段,如果是向上交付到网络层的IP协议的话,这个字段填写0x0800就可以了。在之后的介绍中,我们会对这个字段的认识逐渐清晰。
而前面的目标Mac地址和源Mac地址的大小也表明了Mac地址的大小是一串六个字节的序列,在局域网中的通信当确定好要去哪个主机之后,通信的过程使用的就是Mac地址了,Mac地址一般是世界上唯一的,在Linux中使用ifconfig命令可以查看我们电脑的Mac地址:
其中ether也有以太的意思。
局域网中的通信过程
在上面认识了Mac帧协议的格式之后,接下来我们来认识局域网中是如何通信的:
假设现在主机A向主机H发送一个Mac帧,那么A主机就会通过Mac帧协议封装好Mac帧然后通过网线发送到主机H。此时报文中应该是这样的:
但是局域网中的通信就这么简单吗?当然不是的,我们看到在一个局域网中各个主机相当于是物理上直连的,这就导致了主机A发送出来的Mac帧处于当前局域网中的主机都可以收到,此时也不需要担心,举个例子:当主机B此时收到主机A发送出来的Mac帧之后,主机B确实会收到,但是当这个报文到了数据链路层之后,主机B的数据链路层就会对该报文解包,然后看到报头中的目标Mac地址是MacH不是MacB,那么主机B的数据链库层会直接将该报文丢弃。
上面局域网中的行为就好像一群学生在上课一样,此时老师突然说一句:“张三,你的作业为什么没交?”,此时台下的学生们都听到了这句话,但是除张三外其他同学判断出来不是叫他,所以就不会对这句话做出行为,而张三听到这句话就会处理这句话。
那么由课堂中我们又可以衍生出来局域网中的一个特性:那就是在一个教室里面,老师在讲台上讲课,下面的学生也在说话,这就会导致教室变得非常混乱,学生无法从中获取有效的信息,并且在这种情况下学生越多,场面会越混乱。而这也与局域网非常相似,在局域网中由于各个主机之间是物理上直连的,这就会出现多台主机同时向该局域网中发送信息,但是局域网只有一个啊,这就像两个人在一个平静的水面上各投入一颗石子,就会导致双方的波纹被打乱,此时局域网中传递的信息也会被破坏,这些信息都是二进制被破坏就无法复原了,而这种在局域网中多台主机同时向局域网中发送信息,导致各自信息被破坏的情况就叫做碰撞。而一个局域网一般也就是一个碰撞域。
既然局域网中有着这样的问题,那么就会有相应的解决方案,那就是碰撞检测和碰撞避免:
碰撞检测:简单来说就是当一台主机发送出Mac帧之后,既然其他主机能收到该Mac帧,那就说明自己也能收到该
Mac帧,此时该主机就会对该Mac帧进行检验,当数据发生不一致时,就认为出现了碰撞的情况
碰撞避免:而当确定出现了碰撞之后,检测出碰撞的主机们就会进入一段休眠时间,休眠时间是随机的,过了休眠时
间就会继续发送Mac帧。这样也是为了给其他没有出现碰撞的主机提供发送的机会
除此之外,在一些规模较大的局域网中,上面的处理方式会导致局域网中的通信效率较低,所以在数据链路层中有一个设备叫做交换机:
当交换机工作在一个局域网中时,随着局域网中主机的通信,交换机会记住哪些主机处于它的一边,那些主机处于它的另一边。假如此时交换机已经清楚了局域网中各个主机的位置,那么此时主机A向主机E发送一个Mac帧,当这个报文到达交换机的时候,交换机就会判断出这个报文的发送端和接收端处于同一边,所以交换机就不会把这个报文发送到它的另一端,也就是说主机C、D、G、H都不会收到这个报文。那么这样的处理方式相当于减少了局域网中的主机数量,大大减少了局域网中发生数据碰撞的概率,提高了通信效率,而这种方式也叫做划分碰撞域。
所以一般来说在同一局域网中同一时间内,只允许一台主机进行数据的发送。而这中现象可以类比操作系统中的互斥,此时局域网就相当于一个临界资源,而交换机就相当是信号量,把这一份资源分成多份使用。
在认识上面的局域网通信过程之后,我们终于可以认识到了为什么Mac帧规定了mtu最大是1500,如果mtu过于大的话则会导致局域网中发生碰撞的概率增大。而前面也说过mtu一般来说是1500字节,这就导致TCP中MSS一般是1460,但是这个值不是一定的,所以关于MSS,TCP协议会在双方主机三次握手时进行MSS的协商,而这个关于MSS大小的字段则是处于TCP报头的边长选项中。
3. ARP协议
在上面认识局域网通信原理的时候,不知道有没有人意识到有点不对劲,哪里不对劲呢?那就是当主机A给主机H发送Mac帧的时候,主机A好像天然的知道主机H的Mac地址,我们知道在传输层中,对于对端主机的套接字信息来说,对端主机一般都是服务端,而服务端的套接字信息是众人皆知的,所以对端主机的套接字信息我们是知道的。在网络层中,IP协议能够决定出报文的下一跳主机是哪个的原因,是因为在本主机中有路由表作为依据。但是上面主机A天然的知道主机H的Mac地址,这明显又是不正确的,在人为精心设计过的结构中,那有什么天然的事情存在,所以主机A能够得知主机H的Mac地址也不是天然的,而是需要ARP协议来得知主机H的Mac地址,所以要真正认清局域网通信原理,ARP协议也是比较重要的一环。
ARP协议的作用
在认识ARP协议作用之前首先我们要清楚ARP协议在网络层状结构的定位,ARP协议工作在数据链路层,但是在数据链路层中他又处于Mac帧协议的上层协议:
这就意味着,当使用ARP协议封装报文之后再次发送的时候,外层也会封装Mac帧协议在将Mac帧发送到局域网,此时Mac帧中的有效载荷就是ARP报文。而这样在一层中网络协议之上还有网络协议的现象不止出现在数据链路层中,这在网络层中也有体现,那就是IP协议之上还有诸如ICMP/IGMP的网络协议,ICMP主要负责网络控制和错误报告,而IGMP则专注于多播组的管理和优化。
在上面引出ARP协议的过程中,我们知道在一个局域网中,主机与主机之间Mac地址的得知不是天然的,而是依靠ARP协议。那么ARP协议的作用是什么呢?
用通俗的话来说就是:主机A在局域网中叫了一声:“我是主机A,IP地址是IPA,Mac地址是MacA,我想问IP地址是IPH的主机的Mac地址是多少?”。
在一个局域网中,当主机A在局域网中叫了一声,这其实是代表主机A在局域网中发送了一个广播报文,而广播报文意味着主机A发送出去报文的目标Mac地址是全f,也就是0xff ff ff ff ff ff。这时局域网中所有的主机都会收到这个报文,由于这是广播报文,所以所有的主机都会将这个报文接收到数据链路层中,并对该Mac帧进行解包,并得知这是一个ARP报文,所以向上交付给ARP协议,然后主机中的ARP协议再次判断出他要询问的主机IP地址是IPH,那么主机IP地址非IPH的主机就会丢掉这个报文,主机H就会对该报文作出回应,主机A就会得知主机H的Mac地址,从而两台主机在局域网中开始进行正常的通信。
所以ARP协议的作用就是通过目标主机的IP地址来获取目标主机的Mac地址。
ARP协议格式
关于硬件类型是指在局域网中所使用的技术,我们一般使用的都是以太网,以太网代表1.
协议类型,这里的协议指的是要转换的地址类型,我们是要使用IP地址来找Mac地址,所以是0x0800.
硬件地址长度对应以太网地址长度即Mac地址长度为6字节.
协议地址长度就是IP地址长度为4字节.
由于我们现在是向局域网中询问目标主机Mac地址,所以目标以太网地址是广播地址.
关于op字段,在上面介绍ARP协议字段的时候我们知道ARP协议即会发出询问,也会得到应答,所以这里的op字段
就用来表示询问和应答,其中1表示询问,2表示应答.
ARP报文发送过程
那么我们现在就来演示一下,主机A是如何得知主机H的Mac地址的:
首先主机A要发送一个正常的IP报文,通过IP协议知道,该报文发送的下一跳主机是IPH,于是这个IP报文被送到数据链路层Mac协议的sk_buff的发送队列中并封装成为Mac帧,但是在封装的过程中,主机A发现他不知道主机H的Mac地址,所以主机又会让ARP协议来获取主机H的Mac地址,那么主机A就会封装一个ARP报文:
然后将这个报文送给Mac帧协议,再将ARP报文封装成Mac帧:
ARP报文封装Mac帧时,Mac帧报头中协议类型填0806。
然后就会将这个Mac帧发送到局域网中,然后各个主机都会收到该报文,但是IP地址不是IPH的主机在收到该报文之后,经过解包得到ARP报文之后就会得知这个ARP报文是一个请求报文,但是找的目标主机不是自己,所以就会将这个报文直接丢弃。而主机H收到该Mac帧并解包向上交付给ARP协议,然后ARP协议判断出这是一个请求报文,并且正好请求的就是自己的Mac地址,所以主机H的ARP协议就会对这个报文进行应答,构建一个应答ARP报文:
然后将该ARP报文交付给下层Mac帧协议,封装为Mac帧:
再然后就把这个Mac帧发送到局域网中,局域网中Mac地址不是MacA的主机收到该Mac帧之后判断出目标Mac地址不是自己的Mac地址,所以将Mac帧直接丢弃,而主机A收到该报文之后,知道该报文的目标Mac地址就是MacA,所以对该Mac帧进行解包,根据协议类型向上交付给ARP协议,ARP协议判断出这是一个应答报文,目标主机就是自己,所以此时主机A就得知了IPH对应的Mac地址就是MacH,此时最开始主机A要发送的报文就可以封装成Mac帧正常发送了。
需要注意的是,主机A得知主机H的Mac地址是有时间限制的,一般是十几分钟,这样做的原因是防止局域网中某些主机更换网卡导致Mac地址发生更改,这样的话,主机A就永远无法发送Mac帧到目标主机了。主机中缓存的Mac地址可以通过arp -a查看:
4. 额外的知识
其实在数据链路层中Mac协议之上还有一个协议RARP,这个协议的作用时通过Mac地址找IP地址,那么这个功能很显然较之前的协议是比较简单的:
在上面得知了局域网中的通信方式之后,我们或许现在可以回答出应用层的报文数据为什么要加密了,如果不加密的话假如你在一个公共场合连接了人家的网络,而处于这个局域网中的有心之人通过一些工具,来更改自己的网卡对于Mac帧的接收模式(不会丢弃Mac帧)的话,那么他可以轻而易举获取到你的一切上网的行为,这是非常危险的。
中间人
除了上面通过在局域网中更改自己网卡的模式来获取局域网中的Mac帧,还有一种方法也可以只获取到目标主机的Mac帧,而这种方式也可以让局域网中的任何一台主机被离线,那就是成为中间人。
成为中间人的方式也比较简单,它是利用了Mac地址缓存的特性,我们在上面知道Mac地址缓存是有时间限制的,这就意味着,当有相同类型的ARP应答报文到达主机时,主机总是会使用最新的那个报文中的Mac地址,那么利用这个特性,我们可以使用某些网络工具,来同时向局域网中的某一台主机(比如主机A)发送ARP报文,而报文内容就是“我是默认出口路由器R,我的IP地址是IPR,我的Mac地址是MacM”,并且同时向该局域网中的默认出口路由器发送ARP报文“我是主机A,我的IP地址是IPA,我的Mac地址是MacM”。这样的话无论是主机A要上网传出数据,还是路由器给主机A返回数据,他们的终点都是中间人主机M,在经过某种操作主机M再对这些数据进行修改然后再发送到它最终的目标主机。这就是成为中间人。
成为中间人,之后我们也可以不转发数据,并且只对默认出口路由或者目标主机进行修改Mac地址,这样的话就会将目标主机离线,导致目标主机无法上网,这样的现象或许通过重启可以解决。
一些比较重要的网络协议
DNS
我们在学习了网络之后,我们知道网络世界中两台主机之间进行通信是需要获取对方的套接字信息的,包括我们使用浏览器访问我们制作好的服务端时使用的也是IP地址+端口的方式,但是为什么我们平时使用浏览器访问大部分网站时,都不使用IP地址+端口号而是诸如www.baidu.com呢?这其中的原因就是因为DNS协议。
DNS协议又叫做域名解析协议,他是将一个域名解析为IP地址协议。
而域名一般也被分为三个部分:
com: 一级域名. 表示这是一个企业域名. 同级的还有 "net"(网络提供商), "org"(非盈利组织) 等.(比如Linux内核网站)
baidu: 二级域名, 公司名.
www: 只是一种习惯用法. 之前人们在使用域名时, 往往命名成类似于ftp.xxx.xxx/www.xxx.xxx这样的格式, 来表示主机
支持的协议.我们发现www其实可带可不带。
ICMP
ICMP协议是一个网络层协议,我在上面的部分提到过。
一个新搭建好的网络, 往往需要先进行一个简单的测试, 来验证网络是否畅通; 但是IP协议并不提供可靠传输. 如果丢包了, IP协议并不能通知传输层是否丢包以及丢包的原因.
ICMP正是提供这种功能的协议; ICMP主要功能包括:
确认IP包是否成功到达目标地址.
通知在发送过程中IP包被丢弃的原因.
ICMP也是基于IP协议工作的. 但是它并不是传输层的功能, 因此人们仍然把它归结为网络层协议;
ICMP只能搭配IPv4使用. 如果是IPv6的情况下, 需要是用ICMPv6;
我们在网络传输数据的过程中,虽然TCP提供了可靠性,但是对于报文发出没有得到应答的情况,TCP协议只能把它归结于丢包了,显然报文没有得到应答丢包只是其中一个原因,他也可能是网络传输过程中的某一个节点因为某些原因无法正常工作了,所以ICMP协议就是用来检测网络传输过程中的信道是否健康。大致的原理就是发送端主机向目标主机发送ICMP报文,假如能发送到目标主机,目标主机的ICMP协议会返回一个ICMP报文,其中的字段会表示当前信道是健康的,但是如果是中途某一个节点出了问题的话,此时该节点的ICMP就会得出错误原因,并且返回携带出错信息的ICMP报文给发送端主机,而ICMP报文格式如下:
而关于ICMP协议我们还认识一个比较熟悉的命令,那就是ping命令,这个命令我们一般来检测这台机器网络是否正常等等功能,它就是基于ICMP协议,基于网络层。