在IP 中,协议号表示 IP 头部后面的包内容的类型;而在以太网中,我们可以认为以太网类型后面就是以太网包的内容,而以太类型就表示后面内容的类型。以太网包的内容可以是IP、ARP等协议的包,它们都有对应的值,这也是根据规则来确定的。 在生成 MAC头部时,只要设置表中的3个字段就可以了。
方便起见,我们按照从下往上的顺序来对表进行讲解。首先是“以太类型”,这里填写表示 IP协议的值0800(十六进制)。接下来是发送方MAC地址,这里填写网卡本身的 MAC地址。MAC地址是在网卡生产时写入ROM里的,只要将这个值读取出来写入MAC头部就可以了。对于多块网卡的情况,请大家回想一下设置发送方IP地址的方法。设置发送方IP地址时, 我们已经判断出了从哪块网卡发送这个包,那么现在只要将这块网卡对应的 MAC地址填进去就好了。 前面这些还比较简单,而接收方MAC地址就有点复杂了。只要告诉以太网对方的 MAC的地址,以太网就会帮我们把包发送过去,那么很显然这里应该填写对方的 MAC地址。然而,在这个时间点上,我们还没有把包发送出去,所以先得搞清楚应该把包发给谁,这个只要查一下路由表就知道了。在路由表中找到相匹配的条目,然后把包发给Gateway列中的IP 地址就可以了。 既然已经知道了包应该发给谁,那么只要将对方的 MAC 地址填上去就好了,但到这里为止根本没有出现对方的 MAC 地址,也就是说我们现在根本不知道对方的 MAC 地址是什么。因此,我们还需要执行根据 IP 地址查询 MAC 地址的操作
1.ARP查询路由器的MAC地址
这里我们需要使用ARPC,它其实非常简单。在以太网中,有一种叫作广播的方法,可以把包发给连接在同一以太网中的所有设备。ARP 就是利用广播对所有设备提问:“××这个IP地址是谁的?请把你的MAC地址 告诉我。”然后就会有人回答:“这个IP地址是我的,我的MAC地址是××××。如果对方和自己处于同一个子网中,那么通过上面的操作就可以得到对方的 MAC地址。
然后,我们将这个MAC地址写入MAC头部,MAC 头部就完成了。 不过,如果每次发送包都要这样查询一次,网络中就会增加很多ARP 包,因此我们会将查询结果放到一块叫作 ARP 缓存的内存空间中留着以后 用。也就是说,在发送包时,先查询一下ARP缓存,如果其中已经保存了对方的 MAC地址,就不需要发送ARP查询,直接使用ARP缓存中的地址,而当ARP缓存中不存在对方MAC地址时,则发送ARP查询。显示ARP缓存的方法和MAC地址的写法如图2.20和图所示,供大家参考。
有了ARP缓存,我们可以减少ARP包的数量,但如果总是使用ARP缓存中保存的地址也会产生问题。例如当IP地址发生变化时,ARP缓存的内容就会和现实发生差异。为了防止这种问题的发生,ARP 缓存中的值在经过一段时间后会被删除,一般这个时间在几分钟左右。这个删除的操作非常简单粗暴,不管ARP缓存中的内容是否有效,只要经过几分钟就全部删掉,这样就不会出问题了。当地址从 ARP 缓存中删除后,只要重新执行一次 ARP 查询就可以再次获得地址了。 上面这个策略能够在几分钟后消除缓存和现实的差异,但IP地址刚刚发生改变的时候,ARP缓存中依然会保留老的地址,这时就会发生通信的异常。将MAC头部加在IP头部的前面,整个包就完成了
到这里为止,整个打包的工作是由IP模块负责的。有人认为,MAC头部是以太网需要的内容,并不属于IP的职责范围,但从现实来看,让IP负责整个打包工作是有利的。如果在交给网卡之前,IP模块能够完成整个打包工作,那么网卡只要将打好的包发送出去就可以了。对于除 IP 以外的其他类型的包也是一样,如果在交给网卡之前完成打包,那么对于网卡来说,发送的操作和发送 IP 包是完全相同的。这样一来,同一块网卡就可以支持各种类型的包。至于接收操作,我们到后面会讲,但如果接收的包可以原封不动直接交给IP模块来处理,网卡就只要负责接收就可以了。这样一来,一块网卡也就能支持各种类型的包了。与其机械地设计模块和设备之间的分工,导致网卡只能支持IP包,不如将分工设计得现实一些,让网卡能够灵活支持各种类型的包。

四、何为以太网

1.以太网的定义