发给 127.0.0.1 的数据包到底走不走网卡?发给自己的 en0 地址呢?127.0.0.2 在 macOS 上能用吗?回环与 Unix 域套接字谁更快?这篇用路由表、tcpdump 和一组小基准把这些都量一遍。
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384 options=1203<RXCSUM,TXCSUM,TXSTATUS,SW_TIMESTAMP> inet 127.0.0.1 netmask 0xff000000 inet6 ::1 prefixlen 128 inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1 route get 127.0.0.1 → interface=lo0 gateway=(直连) route get <本机局域网IP> → interface=lo0 gateway=(直连) route get <本机局域网IP> → interface=en0 gateway=(直连) 注意:发往本机自己 en0 地址的包,路由表里的出口也是 lo0——不是 en0
lo0 的 MTU 是 16384,地址只有 127.0.0.1 与 ::1;路由表里 127.0.0.1 的出口是 lo0,本机自己 en0 地址的出口也是 lo0。
连接 <本机局域网IP>:9400:lo0 上抓到 12 个包,源 / 目的地址是 <本机局域网IP> → <本机局域网IP>;en0 上抓到 0 个包 地址是 en0 的,包却在 lo0 上走:内核发现目的地址属于自己,直接环回,不经过网卡
发往本机任一地址的包,路由表出口都是 lo0;只有外部地址才走真实网卡。所以连自己的 en0 地址,包在 lo0 上,抓 en0 一个也看不到。
连 127.0.0.1:成功(服务端看到对端 127.0.0.1) 连 127.0.0.2:TimeoutError: timed out 连 127.1.2.3:TimeoutError: timed out 对比 Linux:整个 127.0.0.0/8 默认都路由到 lo,连 127.0.0.2 直接成功;macOS 需要先给 lo0 加别名(ifconfig lo0 alias 127.0.0.2,要 root),本机没做
macOS 上 lo0 只配了 127.0.0.1(以及 ::1),连 127.0.0.2 会超时;Linux 则整段 127/8 都是回环。
127.0.0.1: min/avg/max/stddev = 0.077/0.178/0.310/0.080 ms 本机自己的 en0 地址 <本机局域网IP>: min/avg/max/stddev = 0.119/0.230/0.457/0.087 ms 网关 <本机局域网IP>: min/avg/max/stddev = 2.600/4.211/17.127/3.407 ms
回环 ping 平均 0.178 ms、本机自己的地址 0.230 ms,真实的一跳(网关)4.211 ms 且抖动大。
TCP 127.0.0.1 1 字节乒乓平均往返 20.9 µs UDP 127.0.0.1 1 字节乒乓平均往返 24.5 µs Unix 域套接字 1 字节乒乓平均往返 6.4 µs TCP 127.0.0.1 单向灌 1 GiB 吞吐 6654 MiB/s Unix 域套接字 单向灌 1 GiB 吞吐 1524 MiB/s
Unix 域套接字绕过 IP / TCP,小消息往返只要 6.4 µs;TCP 回环 20.9 µs;但大块数据灌入的吞吐在这个系统上 TCP 回环更高。