今天这篇文章,很有意思,它来源于我曾经的一次真实面试里的其中一个小问题。当时是终面,面我的是那家公司的技术顾问,在面试前 hr 还让我看了他的履历,是一位 1996 年就进了麻省理工计算机系的大佬。
属实有被震惊到,什么概念?1996 年,没记错的话那是个用 BP 机和大哥大的年代?有几个人能用上电脑?又有几个人有这种机会能出国深造。
这是哪部爽文小说的主人公剧情?
就算放到现在,这也是非常强的事情。
我这辈子是没希望了,也不知道我的儿子或者孙子辈有没有机会能做到。
也就是说,这位大佬,至少领先了我两代人。
那一天,我感受到了,那种跨越时代的碾压感。
好了,不讲骚话了,直接开始主题吧。
我们知道,如果你知道某台电脑的 IP,就可以向这个 IP 发起连接请求,建立连接后就可以操作收发数据。
五层网络协议对应的消息体变化分析要发送的数据,会在网络层里加入 IP 头。
ip 报头这里面最重要的是发送端和接收端的 IP 地址。这个 IP 地址就像是一个门牌号一样,有了它,数据包就能在这个纷繁复杂的网络世界里找到该由谁来接收这个数据包。
所以说上面的网络通信离不开 IP。
假设我有一台新买的电脑,还没联网呢,这时候拿着新买的网线,插入网线口,网线插口亮起来了。
然后就可以开始用它上网了。
那么问题来了。
刚插上网线,电脑怎么知道自己的 IP 是什么?怎么就突然能上网了呢?
这个话题,我们从 DHCP 聊起吧。
DHCP 是什么
插上网线之后,获得 IP 的方式主要有两种。
第一种是,自己手动在电脑里配。像下图那样,是 macOS 的一个截图,在选择手动配置之后,除了 IP 地址还需要配上子网掩码和路由器的地址。
手动配 IP这就很不科学了,电脑又不只是卖给程序员,这几个词对于大部分普通人来说,比赋能抓手闭环这种黑话还要难理解。
大部分人没事都不应该去配这玩意。
有没有办法可以让这些 IP 信息自动获得?
有,这就是第二种获取 IP 的方式,DHCP(Dynamic Host Configuration Protocol,动态主机配置协议)。
DHCP 自动生成 IP通过 DHCP,在联网之后可以自动获取到本机需要的 IP 地址,子网掩码还有路由器地址。
DHCP 的工作原理
DHCP 的工作原理也非常简单。
说白了,就是向某个管 IP 分配的服务器,也就是 DHCP 服务器,申请 IP 地址。其实一般家里用的路由器就自带这个功能。
整个操作流程分为 4 个阶段。
DHCP 协议DHCP Discover:在联网时,本机由于没有 IP,也不知道 DHCP 服务器的 IP 地址是多少,所以根本不知道该向谁发起请求,于是索性选择广播,向本地网段内所有人发出消息,询问 " 谁能给个 IP 用用 "。
DHCP Offer:不是 DHCP 服务器的机子会忽略你的广播消息,而 DHCP 服务器收到消息后,会在自己维护的一个 IP 池里拿出一个空闲 IP,通过广播的形式给回你的电脑。
DHCP Request:你的电脑在拿到 IP 后,再次发起广播,就说 "这个 IP 我要了"。
DHCP ACK:DHCP 服务器此时再回复你一个 ACK,意思是 "ok 的"。你就正式获得这个 IP 在一段时间(比如 24 小时)里的使用权了。后续只要 IP 租约不过期,就可以一直用这个 IP 进行通信了。
到这里,问题来了
为什么要有第三和第四阶段
大家有没有发现,在 Offer 阶段,其实你的机子就已经拿到了 IP 了,为什么还要有后面的 Request 和 ACK 呢?是不是有些多此一举?
这是因为本地网段内,可能有不止一台 DHCP 服务器,在你广播之后,每个 DHCP 服务器都有可能给你发 Offer。
本着先到先得的原则,你的机子一般会对第一个到的 Offer 响应 DHCP Request,目的是为了确认 offer,在你确认 Offer 这段时间内,DHCP 服务器确认这个 IP 还没被分出去,你才可以安心使用这个 IP。
像不像你找工作的过程?
你海投简历(DHCP Discover),然后拿到了多个 offer (DHCP Offer)。
这时候事情还没完,你一般会跟 HR 说:" 你给我两天时间,我要跟家里人商量下 "。
HR 也会对你说:" 那你尽快确认,我这边还有不少候选人等着 "。
之后你考虑下来觉得不错,跟 HR 说要接这个 Offer(DHCP Request),HR 看了下这个岗位还在,才能确认让你第二天来上班(DHCP ACK)。如果这个公司的岗位已经招到其他候选人了,第四阶段的消息就会改为发 DHCP NAK,意思是拒绝了你的接 Offer 请求。
DHCP 抓包
光看原理是有些枯燥,我们可以尝试下抓包看下数据。
在命令行里执行下面的命令,可以强行让电脑的 en0 网卡重新走一遍 DHCP 流程。
sudo ipconfig set en0 DHCP
en0 可以替换成其他网卡,比如 eth0 啥的。
这时候就可以抓到相关的数据包。
我们可以看到蓝色的四个数据包,分别对应上面提到的四个 DHCP 阶段。
其中第二阶段中的 DHCP Offer 里会返回给我们需要的 IP、子网掩码、路由器地址以及 DNS 服务器地址。
offer 阶段另外,通过抓包,我们可以发现 DHCP 是应用层的协议,基于传输层 UDP 协议进行数据传输。
那么问题又来了。
为什么 DHCP 用 UDP,能不能改用 TCP?
按道理说,UDP 能做到的,TCP 一般也能做到。但这次真不行。
主要原因还是因为 TCP 是面向连接的,而 UDP 是无连接的。
所谓 "连接",他就只有一个发送端和一个接收端,就跟水管一样。
而 DHCP 由于一开始并不知道要跟谁建立连接,所以只能通过广播的形式发送消息,注意,小细节,广播。
广播寻找 DHCP 服务器.drawio同样是在本地网段内发广播消息,UDP 只需要发给 255.255.255.255。它实际上并不是值某个具体的机器,而是一个特殊地址,这个地址有特殊含义,只要设了这个目的地址,就会在一定本地网段内进行广播。
而 TCP 却不同,它需要先建立连接,但实际上 255.255.255.255 对应的机器并不存在,因此也不能建立连接。如果同样要做到广播的效果,就需要先得到本地网段内所有机器的 IP,然后挨个建立连接,再挨个发消息。这就很低效了。
因此 DHCP 选择了 UDP,而不是 TCP。
为什么第二阶段不是广播,而是单播。
另外一个小细节不知道大家注意到没,上面在提到 DHCP Offer 阶段时,提到的是 DHCP 服务器会使用广播的形式回复。但抓个包下来却发现并不是广播,而是单播。
其实,这是 DHCP 协议的一个小优化。原则上大家在 DHCP offer 阶段,都用广播,那肯定是最稳的,目标机器收到后自然就会进入第三阶段 DHCP Request。而非目标机器,收到后解包后发现目的机器的 mac 地址跟自己的不同,也会丢掉这个包。
但是问题就出在,这个非目的机器需要每次都在网卡收到包,并解完包,才发现原来这不是给它的消息,这。。。真,有被打扰到。
如果本地网段内这样的包满天飞,也浪费机器性能。
如果能用单播,那当然是最好的。但这时候目的机器其实并没有 IP 地址,有些系统在这种情况下能收单播包,有些则认为不能收,这个跟系统的实现有关。因此,对于能收单播包的系统,会在发 DHCP Discover 阶段设一个 Broadcast flag = 0 (unicast) 的标志位,告诉服务器,支持单播回复,于是服务器就会在 DHCP Offer 阶段以单播的形式进行回复。
Discover 要求使用单播回复是不是每次联网都要经历 DHCP 四个阶段?
只要想联网,就需要 IP,要用 IP,就得走 DHCP 协议去分配。
但大家也发现了,DHCP 第一阶段和第二阶段都可能会发广播消息。对于家用电脑还好,插个网线,之后就雷打不动。但像手机这样的移动设备,是要带着到处跑的,坐个地铁,进个电梯,公司里到处走走,都可能会涉及到网络切换。
这每次都要来一个完整的四阶段,各种广播消息满天飞,其实对网络环境不太友好。
于是问题叒来了,是不是每次联网都要经历 DHCP 四个阶段?
当然不需要。
我们会发现每次断开 wifi 再打开 wifi 时,机子会经历一个从没网到有网的过程。
这时候去抓个包,会发现。
其实只发生了 DHCP 的第三和第四阶段。这是因为机子记录了曾经使用过 192.168.31.170 这个 IP,重新联网后,会优先再次请求这个 IP,这样就省下了第一第二阶段的广播了。
另外需要注意的是,抓包图里 DHCP Request 之所以出现两次,是因为第一次 Request 发出后太久没得到回应,因此重发。
DHCP 分配下来的 IP 一定不会重复吗?
一般来说 DHCP 服务器会在它维护的 IP 池里找到一个没人用的 IP 分配给机子,
这个 IP 如果重复分配了,那本地网段内就会出现两个同样的 IP,这个 IP 下面却对应两个不同的 mac 地址。但其他机器上的 ARP 缓存中却只会记录其中一条 mac 地址到 IP 的映射关系。
于是,数据在传递的过程中就会出错。
因此本地网段内 IP 必须唯一。
那么 DHCP 分配下来的 IP 有没有可能跟别的 IP 是重复的?
都这么问了,那肯定是可能的。
有两个常见的情况会出现 IP 重复。
文章开头提到,IP 是可以自己手动配的,自己配的 IP 是有可能跟其他 DHCP 分配下来的 IP 是相同的。解决方案也很简单,尽量不要手动去配 IP,统一走 DHCP。或者在 DHCP 服务器里维护的 IP 范围里,将这条 IP 剔除。
一个本地网段内,是可以有多个 DHCP 服务器的,而他们维护的 IP 地址范围是有可能重叠的,于是就有可能将相同的 IP 给到不同的机子。解决方案也很简单,修改两台 DHCP 服务器的维护的 IP 地址范围,让它们不重叠就行了。
不过吧,上面的解决方案,都需要有权限去修改 DHCP 服务器。
得到 DHCP ACK 之后立马就能使用这个 IP 了吗?
这就好像在问,拿到 offer 之后你是第一时间就去上班吗?
不。
你会先告诉你的同事同学朋友,甚至会发朋友圈。
你的机子也一样。
在得到 DHCP ACK 之后,机子不会立刻就用这个 IP。
而是会先发三条 ARP 消息。
大家知道 ARP 消息的目的是通过 IP 地址去获得 mac 地址。所以普通的 ARP 消息里,是填了 IP 地址,不填 mac 地址的。
但这三条 ARP 协议,比较特殊,它们叫无偿 ARP(Gratuitous ARP),特点是它会把 IP 和 mac 地址都填好了,而且填的还是自己的 IP 和 mac 地址。
目的有两个。
一个是为了告诉本地网段内所有机子,从现在起,xx IP 地址属于 xx mac 地址,让大家记录在 ARP 缓存中。
另一个就是看下本地网段里有没有其他机子也用了这个 IP,如果有冲突的话,那需要重新再走一次 DHCP 流程。
在三次无偿 ARP 消息之后,确认没有冲突了,才会开始使用这个 IP 地址进行通信。
这种行为,实际上就跟你拿了 offer 之后发了这么个朋友圈没啥区别。
而且,还连发了三条。
别骂了,图是 P 的,我没这么发过
秀 offer,offer 冲突了不可怕。秀对象秀冲突了才可怕。
如果你朋友圈里有这种人,答应我,删了吧。
总结
电脑插上网线,联网后会通过 DHCP 协议动态申请一个 IP,同时获得子网掩码,路由器地址等信息。
DHCP 分为四个阶段,分别是 Discover,Offer,Request 和 ACK。如果曾经连过这个网,机器会记录你上次使用的 IP,再次连接时优先使用原来的那个 IP,因此只需要经历第三第四阶段。
DHCP 是应用层协议,考虑到需要支持广播功能,底层使用的是 UDP 协议,而不是 TCP 协议。
DHCP 分配下来的 IP 是有可能跟某台手动配置的 IP 地址重复的。
DHCP 得到 IP 之后还会发 3 次无偿 ARP 通告,在确认没有冲突后开始使用这个 IP。
最后给大家留个问题吧。我们上面的 IP 都是从 DHCP 服务器上申请的,在服务器返回 DHCP Offer 的时候,可以看到上面写了 DHCP 服务器的 IP。比如 192.168.31.1,这明显是个局域网内的 IP,但这能说明,你的 DHCP 服务器一定在这个局域网里吗?
参考资料
《图解 TCPIP》
本文来自微信公众号:小白 debug (ID:xiaobaidebug),作者:小白