之前处理了一个 bug,软件在一些使用场景下会发不出 udp 包,排查之后发现是调用 sendto() 函数成功,然而使用 wireshark 却抓不到 udp 包。

然后在排查过程中查看 arp 表时,结果意外发现居然有两张网卡是被设置成同一个网段 的 ip 了,摔啊!

于是看了一下路由表,发现果然是未使用的网卡 B(192.168.2.56)的记录在网卡 A(192.168.2.204)之前,而设备是连接在网卡 A 上的。

这就导致通讯时系统会首先使用 B 来发送数据包,而当设备的 mac 地址没有被网卡缓存时,B 会首先发送 arp 广播包获取设备的 mac 地址。当然连在网卡 A 上的设备 C 是没法回应的,然后数据包会因为 B 没有目的 ip 的物理地址而发送失败。

另外当 B 的 arp 失败后会在 B 的 arp 表中生成一个该 ip 地址的记录项,指示该 ip 对应无效的 mac 地址(00-00-00-00-00-00),根据微软的描述,默认情况下该记录项会在15到45秒后刷新。在 B 的记录清除之前再发起通讯请求时系统会选择使用 A 发送 arp 广播,这时设备便能接收数据和正常通讯。否则当 B 中的无效记录被清除后会继续使用 B,通讯依旧会失败。

总结一下就是两张同网段 ip 的网卡,当两张网卡的 arp 表都没有对应的记录时,系统会根据路由表中记录的顺序选择第一个网卡进行通讯(启用、禁用网卡可改变路由表的记录顺序)。如果网卡的 arp 表中缓存了对应的 mac 则会直接使用相应的网卡进行通讯。
当然最好还是不要设为同一个网段……