2.5.3 生成包含接收方 IP 地址的 IP 头部
IP头部包含的内容浏览器
IP 模块接受 TCP 模块的委托负责包的收发工做,它会生成 IP 头部并附加在 TCP 头部前面。缓存
IP 头部包含的内容如表 2.2 所示,其中最重要的内容就是 IP 地址,它表示这个包应该发到哪里去。网络
接受方IP地址:应用程序告知TCP,TCP告知IP模块spa
这个地址是由 TCP 模块告知的,而 TCP 又是在执行链接操做时从应用程序那里得到这个地址的,所以这个地址的最初来源就是应用程序。操作系统
IP 不会自行判断包的目的地,而是将包发往应用程序指定的接收方,即使应用程序指定了错误的 IP 地址,IP 模块也只能照作。设计
固然,这样作确定会出错,但这个责任应该由应用程序来承担。对象
在链接操做中发送第一个 SYN 包时就可能发生这样的状况,一旦 TCP 链接完毕,就已经确认可以正常和对方进行包的收发,这时就不会发生这样的状况了。blog
发送方的IP地址来自使用的网卡对应的IP地址接口
IP 头部的“接收方 IP 地址”填写通讯对象的 IP 地址。内存
发送方 IP 地址须要判断发送所使用的网卡,并填写该网卡的 IP地址。
如何判断把包交给哪块网卡
和路由器使用 IP 表判断下一个路由器位置的操做是同样的。
由于协议栈的 IP 模块与路由器中负责包收发的部分都是根据 IP 协议规则来进行包收发操做的,因此它们也都用相同的方法来判断把包发送给谁。
查看路由表
这个“IP 表”叫做路由表,咱们将在第 3 章探索路由器时详细介绍它的用法,这里先简单讲个大概。
如图 2.18 所示,咱们能够经过 route print命令来显示路由表。
Network Destination 网络目标列
例如TCP 模块告知的目标 IP 地址为 192.168.1.21,那么就和第 6 行的 192.168.1 的部分相匹配。
Interface 网络接口列
表示网卡等网络接口,这些网络接口能够将包发送给通讯对象。
Gateway 网关列
表示下一个路由器的 IP 地址,将包发给这个 IP 地址,该地址对应的路由器就会将包转发到目标地址。
默认网关
路由表的第 1 行中,目标地址和子网掩码都是 0.0.0.0,这表示默认网关,若是其余全部条目都没法匹配,就会自动匹配这一行。
这样一来,咱们就能够判断出应该使用哪块网卡来发送包了,而后就能够在 IP 头部的发送方 IP 地址中填上这块网卡对应的 IP 地址。
TCP/UDP协议号
接下来还须要填写协议号,它表示包的内容是来自哪一个模块的。
例如,若是是 TCP 模块委托的内容,则设置为 06(十六进制),若是是 UDP 模块委托的内容,则设置为 17(十六进制),这些值都是按照规则来设置的。
在如今咱们使用的浏览器中,HTTP 请求消息都是经过 TCP 来传输的,所以这里就会填写表示 TCP 的 06(十六进制)。
其余字段内也须要填写相应的值,但对大局没什么影响,咱们会在第3 章进行介绍,这里就先省略了。
注释
①Gateway(网关)在 TCP/IP 的世界里就是路由器的意思。
②若是 Gateway 和 Interface 列的 IP 地址相同,就表示不须要路由器进行转发,能够直接将包发给接收方的 IP 地址。咱们将在第 3 章详细介绍。
2.5.4 生成以太网用的 MAC 头部
MAC头的做用
生成了 IP 头部以后,接下来 IP 模块还须要在 IP 头部的前面加上MAC 头部(表 2.3)。
IP 头部中的接收方 IP 地址表示网络包的目的地,通这个地址咱们就能够判断要将包发到哪里,但在以太网的世界中,TCP/IP 的这个思路是行不通的。
以太网在判断网络包目的地时和 TCP/IP 的方式不一样,所以必须采用相匹配的方式才能在以太网中将包发往目的地,而MAC 头部就是干这个用的。
IP 模块在生成 IP 头部以后,会在它前面再加上 MAC 头部。
MAC 头部是以太网使用的头部,它包含了接收方和发送方的 MAC 地址等信息。
MAC头的结构
MAC 头部的开头是接收方和发送方的 MAC 地址,和 IP 头部中的接收方和发送方 IP 地址的功能差很少,只不过 IP 地址的长度为 32 比特,而 MAC 地址为 48 比特。
IP 地址是相似多少弄多少号这种现实中地址的层次化的结构,而 MAC 地址中的 48 比特能够看做是一个总体。
从表示接收方和发送方的意义上来讲,MAC 地址和 IP 地址是没有区别的。
以太类型字段和 IP 头部中的协议号相似。在 IP 中,协议号表示 IP 头部后面的包内容的类型,以太类型就表示后面内容的类型。
以太网包的内容能够是 IP、ARP等协议的包,它们都有对应的值,这也是根据规则来肯定的。
以太类型
这里填写表示 IP 协议的值 0800(十六进制)。
发送方MAC地址
这里填写网卡自己的 MAC 地址。MAC 地址是在网卡生产时写入 ROM 里的,只要将这个值读取出来写入 MAC 头部就能够了。
对于多块网卡的状况,相似设置发送方 IP 地址的方法。
设置发送方 IP 地址时,咱们已经判断出了从哪块网卡发送这个包,那么如今只要将这块网卡对应的 MAC 地址填进去就行了。
注意
实际上,只有在操做系统启动过程当中对网卡进行初始化的时候才会读取MAC 地址,读取出来以后会存放在内存中,每次执行收发操做时实际上使用的是内存中的值。
此外,读取 MAC 地址的操做是由网卡驱动程序来完成的,所以网卡驱动程序也能够不从网卡 ROM 中读取地址,而是将配置文件中设定的 MAC 地址拿出来放到内存中并用于设定 MAC 头部,或者也能够经过命令输入 MAC 地址。
接收方 MAC 地址
只要告诉以太网对方的 MAC 的地址,以太网就会帮咱们把包发送过去,那么很显然这里应该填写对方的 MAC 地址。
此时咱们尚未把包发送出去,因此先得搞清楚应该把包发给谁,这个只要查一下路由表就知道了。
在路由表中找到相匹配的条目,而后把包发给 Gateway 列中的IP 地址就能够了。
既然已经知道了包应该发给谁,那么只要将对方的 MAC 地址填上去就行了,但到这里为止根本没有出现对方的 MAC 地址,也就是说咱们如今根本不知道对方的 MAC 地址是什么。
所以,咱们还须要执行根据 IP 地址查询 MAC 地址的操做。
2.5.5 经过 ARP 查询目标路由器的 MAC 地址
这里咱们须要使用 ARP ,它其实很是简单。在以太网中,有一种叫做广播的方法,能够把包发给链接在同一以太网中的全部设备。
ARP:Address Resolution Protocol,地址解析协议。
ARP 就是利用广播对全部设备提问:“×× 这个 IP 地址是谁的?请把你的 MAC 地址告诉我。”
而后就会有人回答:“这个 IP 地址是个人,个人 MAC 地址是××××。”
不是这个 IP 地址的设备会忽略广播,什么都不回答。
若是对方和本身处于同一个子网中,那么经过上面的操做就能够获得对方的 MAC 地址。
而后,咱们将这个 MAC 地址写入 MAC 头部,MAC头部就完成了。
若是路由表的设置正确,那么对方应该在同一子网,不然对方没法做出ARP 响应,这时只能认为对方不存在,包的发送操做就会失败。
ARP缓存
不过,若是每次发送包都要这样查询一次,网络中就会增长不少 ARP包,所以咱们会将查询结果放到一块叫做 ARP 缓存的内存空间中留着之后用。
在发送包时,先查询一下 ARP 缓存,若是其中已经保存了对方的 MAC 地址,就不须要发送 ARP 查询,直接使用 ARP 缓存中的地址。而当 ARP 缓存中不存在对方 MAC 地址时,则发送 ARP 查询。
显示 ARP 缓存的方法和 MAC 地址的写法如图 2.20 和图 2.21 所示,供你们参考。
ARP缓存会定时删除
若是老是使用 ARP缓存中保存的地址会产生问题。
例如当 IP 地址发生变化时,ARP 缓存的内容就会和现实发生差别。
为了防止这种问题的发生,ARP 缓存中的值在通过一段时间后会被删除,通常这个时间在几分钟左右。
这个删除的操做很是简单粗暴,无论 ARP 缓存中的内容是否有效,只要通过几分钟就所有删掉,这样就不会出问题了。
当地址从 ARP 缓存中删除后,只要从新执行一次 ARP 查询就能够再次得到地址了。
上面这个策略可以在几分钟后消除缓存和现实的差别,但 IP 地址刚刚发生改变的时候,ARP 缓存中依然会保留老的地址,这时就会发生通讯的异常。
将打包工做交给IP模块的利处
将 MAC 头部加在 IP 头部的前面,整个包就完成了。到这里为止,整个打包的工做是由 IP 模块负责的。
有人认为,MAC 头部是以太网须要的内容,并不属于 IP 的职责范围,但从现实来看,让 IP 负责整个打包工做是有利的。
若是在交给网卡以前,IP 模块可以完成整个打包工做,那么网卡只要将打好的包发送出去就能够了。
对于除 IP 之外的其余类型的包也是同样,若是在交给网卡以前完成打包,那么对于网卡来讲,发送的操做和发送 IP 包是彻底相同的。
这样一来,同一块网卡就能够支持各类类型的包。
至于接收操做,咱们到后面会讲,但若是接收的包能够原封不动直接交给 IP 模块来处理,网卡就只要负责接收就能够了。
这样一来,一块网卡也就能支持各类类型的包了。
与其机械地设计模块和设备之间的分工,致使网卡只能支持 IP 包,不如将分工设计得现实一些,让网卡可以灵活支持各类类型的包。