bigywater.tech
网络协议 · 6

回环接口:发给 127.0.0.1 的包到底走不走网卡

发给 127.0.0.1 的数据包到底走不走网卡?发给自己的 en0 地址呢?127.0.0.2 在 macOS 上能用吗?回环与 Unix 域套接字谁更快?这篇用路由表、tcpdump 和一组小基准把这些都量一遍。

lo0 12 个 / en0 0 个
连本机自己 en0 地址时,两个接口上抓到的包数——流量完全在 lo0
0.178 vs 4.211 ms
ping 127.0.0.1 与 ping 网关的平均往返时间
6.4 µs
Unix 域套接字 1 字节往返(TCP 回环 20.9 µs);但大块吞吐 TCP 6654 MiB/s 反而高于 Unix 域 1524

接口与路由

实测 · 本机执行输出
  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.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 回环更高。

分步演示

回环接口
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64(Apple 芯片)/ Python 3.14.8 / tcpdump(libpcap)/ scapy 2.8 / dpkt / dnspython / h2 / aioquic / OpenSSL / curl 8.7.1;抓包在 lo0(环回)上做,少数实验用真实网卡 en0(这台机器上 en0 是 Wi-Fi,tcpdump 看到的是系统转成以太网格式的帧,所以文中的“以太网头”都指这个 14 字节的头)或访问公网(会在文章里注明);需要丢包 / 延迟 / 限速时,用一个只作用于 lo0 端口 9400-9499 的 dummynet 辅助脚本(netlab);所有服务端都是本机自己起的进程;时间戳取自 tcpdump 的 -tt,数字每次运行会有小幅抖动。路由与接口信息通过 sysd.py 执行 route / ifconfig;第二节同时在 lo0 与 en0 上用 tcpdump 抓包;乒乓和灌入吞吐是 Python 单线程客户端 + 一个服务线程,3 轮中位数,有 GIL 与调度开销,数字只看相对大小
    • 没有验证:Linux 上回环的行为(127/8、lo 的 MTU 65536);给 lo0 加别名后连 127.0.0.2;Unix 域套接字在 SOCK_DGRAM 下的表现;不同缓冲区大小下 TCP 与 Unix 的吞吐;回环上的 TSO 与校验和卸载细节
    京ICP备2026067502号-1京公网安备11010502063487号