调试思路¶
接下来介绍一个通用的调试思路,除了在网络领域特别好用以外,在其他领域也是可以使用的。学习了这个调试思路,你可以有目的地去调试,而不是盲目地去猜问题会在哪里。
首先举一个简单的例子。假设现在实现了一个功能,并且这个功能需要用多个步骤完成,后一个步骤依赖前一个步骤。例如一个功能分三步:
A - B - C
现在这个功能不工作,那么就按照 A-B-C 的顺序,一个一个检查:
- A 步骤是否完成?
- A 步骤是否输出了正确的结果?
- B 步骤是否从 A 步骤获取了正确的输入?
- B 步骤是否完成?
- B 步骤是否输出了正确的结果?
- C 步骤是否从 B 步骤获取了正确的输入?
- C 步骤是否完成?
这个检查乍一看确实觉得麻烦,步骤很多,而且感觉很容易就可以想到。但人总是倾向于偷懒,不愿意逐步去排查问题,总是寄希望于自己能够从茫茫代码中猜到代码哪里有问题,直接把问题解决了。然而往往事与愿违,越是心急越是难以找到问题所在。
而在网络领域里,特别是本实验内,这种方法特别好用:因为网络内的各个节点自然而然地形成了一个多步的逻辑链,例如网络拓扑里是 A 连到 B,B 连到 C,那么 A 要发送数据给 C,一定会经过以下过程:
- A 生成数据,发送给 B
- B 收到 A 的数据,检查是否正确
- B 发送数据给 C
- C 收到 B 的数据,检查是否正确
- C 进行数据的处理
这和前面提到的简单例子完全一致:在网络里面,拓扑上怎么连,数据就怎么走,你只要去路径上每一个点看一看:
- 它收到数据了没
- 它收到数据以后,是否认为数据是正确的
- 数据正确的话,它是否准备把数据再发出去
- 要发送出去的话,它把数据发送给了谁
按照这个方法,很容易就可以定位到是具体哪个节点出现了问题。下面来举一个网络领域的具体的例子:
拓扑:A - B - C
问题:现在 A 要给 C 发送一个 IP 分组,现在发现 C 应用没有收到 IP 分组。
既然拓扑是 A - B - C,那就按照这个顺序来检查:
- 检查 A 发送出 IP 分组了吗?用 wireshark 抓包,发现 A 发送了
- 检查 B 收到 A 发出的 IP 分组了吗?用 wireshark 抓包,发现 B 收到了
- 检查 B 把 A 发送的 IP 分组发送给 C 了吗?用 wireshark 抓包,没看到 B 发送给 C
那就知道是 B 的问题了。这时候再回想 B 在收到 IP 分组的时候,它会做什么:
- 检查 A 发送的 IP 分组是否正确?在 wireshark 里查看 B 收到的 IP 分组,发现 checksum 是对的
- 用 IP 分组的目的地址查询路由表,是否可以查到?在 B 上面查看路由表,发现确实有到 C 的直连路由,并且 IP 分组的目的地址确实是 C
- 既然是直连路由,那么发出去时,目的 MAC 地址应该是 C 的 MAC 地址,那么 C 的 MAC 地址是否在邻居表内?在 B 上面查看邻居表,发现没有 C 的 IP 地址和 MAC 地址
那就说明是 B 的邻居表的问题,这时候就要想邻居表是怎么工作的:到底是 B 没有询问 C 的 MAC 地址呢,还是 C 没有响应 B 的邻居询问请求呢?
这时候在 B 上用 wireshark 抓包,发现确实发送了 MAC 地址询问,并且目的地址确实是 C,而 C 没有回复。那么问题就找到了:问题是 C 没有响应邻居询问请求。在 C 上做了配置的修复,立马网络就恢复正常了。
回顾一下,这个问题从表面上来看,好像是 IP 分组发送不成功,结果到最后,发现是邻居发现协议的问题。如果你一开始就猜是不是 IP 分组写的有问题,对着代码看了半天,也不会看出问题所在。
这时候就需要用出你的专业理论知识:当你知道这个东西是怎么工作的,它要工作需要 ABCD 哪几步,那你就直接按照这个顺序去排查,看看到底卡在哪一步上了。只要你的理论知识足够扎实,就可以逐步抽丝剥茧把实际的问题找到。如果你没有掌握现象背后的原理,很可能就会走向思维的误区,调试不出来。
如果你在调试许久无果,找别人帮忙,最后发现问题和自己最初想的完全不一样的时候,请你再回顾这一段文字,看看自己是不是犯了上面提到的典型错误。