☰
AVD模拟器IP与端口映射实战:从10.0.2.15到adb reverse全解Android联调网络配置
2026/10/16 8:48:45 网站建设 项目流程

简介:面向Android开发者的模拟器(AVD)IP配置参考文档,针对开发中常见的模拟器IP与宿主机不在同一网段、无法联网或与电脑通信困难等问题,给出从启动模拟器到验证生效的完整操作指引。文档从adb环境准备切入,说明如何通过kill-server/start-server解决device not found或offline等报错,并重点介绍getprop查看默认DNS(10.0.2.3)与默认IP(10.0.2.15)的方法,以及用setprop命令将DNS和IP调整到与电脑一致网段的步骤,最后通过getprop确认配置是否生效。资源压缩包仅含1个doc文件,体积约47KB,正文步骤紧凑,命令与输出示例清晰,既适合初学者按图索骥快速上手,也能作为中级开发者在联调测试时随查随用的速查笔记。目前已有2148人学习下载,对于希望解决模拟器联网、本地服务访问等问题的开发者具有直接参考价值。

1. AVD 模拟器的 IP,为什么跟真机完全不是一回事

做 Android 开发时,被 AVD 模拟器的 IP 折腾到怀疑人生,几乎是每个工程师都会经历的事。标题里写“详细操作”,真上手才会发现:模拟器里的 IP 跟宿主机网络根本不在一个网段,在 Android 系统里打开设置手动敲一个静态 IP,保存完转头就丢;想从宿主机访问模拟器里的调试服务,又不知道端口该指到哪。这篇就按我平时排查的路径,把 AVD 模拟器的 IP 地址、默认网关、DNS 和端口映射一次讲清楚。新手能照着命令一步步跑通,老手也能从避坑那章找到几个以前没留意的细节。适合所有用 Android Studio 自装 AVD、并在本机和模拟器之间联调的人。

2. 摸清 AVD 自己的网络家底:三条 adb 命令找到 IP、网关和 DNS

2.1 用 adb shell ip addr 看模拟器网卡的真实 IP

很多开发者以为在虚拟机的“网络设置”里能看到 IP,但 AVD 默认不给你这个入口。最粗暴也最可靠的办法,是直接进入模拟器的 Linux shell 里查网卡。

adb shell ip addr show eth0 # 输出示例: # 3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 # inet 10.0.2.15/24 brd 10.0.2.255 scope global eth0 # valid_lft forever preferred_lft forever

这条命令里的eth0是 AVD 默认的虚拟以太网网卡,inet 10.0.2.15/24就是模拟器真正对外可见的 IP。注意这个地址不是随机分配的局域网 IP,而是 QEMU 用户网络栈内部的一个保留地址:模拟器侧的角色相当于一个 NAT 内网设备。你在 Android 系统的“关于平板电脑”里看到的 IP 也应该是 10.0.2.15,但那个界面在个别定制镜像里可能不显示,所以用 adb shell 最直接。

如果输出里没有inet段,或者网卡名不叫eth0,可以先执行adb shell ip addr不带参数,看所有网卡的名字。部分新版系统镜像里网卡是eth0,也有极少数镜像模拟成wlan0,但地址段都一样,都是 10.0.2.x。看到这个网段,就说明模拟器用的是经典的用户模式网络栈,后面对 IP 的所有设置都要基于这个前提。

2.2 用 ip route 找到默认网关:10.0.2.1 和 10.0.2.2 的分工

拿到 IP 之后,下一步要搞清楚数据从模拟器出去往哪走。同一个模拟器里,网关和宿主机是两个完全不同的概念,混在一起是后面绝大多数连接故障的根源。

adb shell ip route # 输出示例: # default via 10.0.2.1 dev eth0 proto static # 10.0.2.0/24 dev eth0 proto kernel scope link src 10.0.2.15

default via 10.0.2.1告诉你在模拟器内部,只要目标 IP 不在 10.0.2.0/24 网段内,就会交给 10.0.2.1 这个虚拟网关转发。10.0.2.1 实际上就是 QEMU 用户网络栈里的“路由器”。而模拟器里访问宿主机本机服务时,用的却是另一个地址:10.0.2.2。

这个 10.0.2.2 是 QEMU 故意保留的虚拟地址,专门用来映射宿主机的 loopback 接口。举个日常场景:你在宿主机上跑了一个调试服务,监听在127.0.0.1:8080,那么模拟器里访问10.0.2.2:8080就能连上它。反过来,如果你在模拟器里写了localhost:8080,那访问的是模拟器自己,不是宿主机,这个坑特别容易踩。所以在写 App 的时候,要访问宿主机服务,请直接写死在 10.0.2.2,别在代码里占位符写成 localhost。

2.3 用 getprop 确认 DNS:模拟器解析域名走的是谁

IP 和网关都看到了,还有一个经常被忽略的配置是 DNS。模拟器里的域名解析跟普通 Android 真机不太一样,默认情况下它不会直接去读宿主机的网络配置,而是走 QEMU 内置的 DNS 转发器。

adb shell getprop | grep dns # 输出示例: # [net.dns1]: [10.0.2.3]

输出里的10.0.2.3是模拟器默认的 DNS 服务器地址。在 QEMU 的用户模式网络栈下,模拟器把 DNS 查询包发给 10.0.2.3,由宿主机上的 QEMU 进程帮忙转发到真实的 DNS 服务器。这个设计的坑在于:如果你宿主机所在的局域网内网 DNS 解析不了某些内网域名,模拟器也跟着解析不了;如果你发现模拟器里ping baidu.com通了,但 App 里解析内网域名失败,多半是 DNS 配置不对,而不是网络没通。

到这里,AVD 的 IP 全景就清楚了:10.0.2.15 是模拟器自己,10.0.2.1 是网关,10.0.2.3 是 DNS,10.0.2.2 是宿主机 loopback 的别名。记住这四个地址,后面的操作才有依据。

3. 给 AVD“指定”IP:为什么系统设置没用,要改启动参数和端口映射

3.1 在 Settings 里设静态 IP 为什么保存完就失效

很多刚接触 AVD 的开发者会进到模拟器的“设置 > Wi-Fi > 长按当前网络 > 修改网络”,把 IP 设置从 DHCP 改成静态,填上一个 192.168.1.x 之类的地址,点完保存之后再进“状态”一看,IP 还是 10.0.2.15。这不是你没操作对,而是这条路根本走不通。

原因要从模拟器的虚拟硬件说起。AVD 里没有真正的 Wi-Fi 网卡,大多数系统镜像的网络设备走的是虚拟以太网,也就是 eth0。Android 系统设置里的“静态 IP”配置,是给 Wi-Fi 连接用的,它修改的是 WifiService 和 ConnectivityService 里的连接记录,而 eth0 这个网卡根本不由 Wi-Fi 管理器管理。真正给 eth0 分配地址的是模拟器底层的虚拟 DHCP 服务,那个服务跑在 QEMU 进程内部,不读 Android 的数据库。所以无论你在系统设置里怎么填静态 IP,最后生效的都是虚拟 DHCP 给的 10.0.2.15。

那要固定 IP 怎么办?最直接的做法是换一种网络模型,比如让模拟器使用桥接网卡,但这需要管理员权限和额外配置,而且 Android Studio 的 AVD 对桥接支持并不友好,日常开发完全没必要硬刚。绝大多数联调场景,用 adb reverse 或端口重定向就足够了,下面几节就是这俩方案。

3.2 启动 AVD 时用 emulator 参数指定 DNS 和网络延迟

如果只是想改模拟器出口网络的某些属性,比如 DNS、网速、延迟,不需要进系统设置,在启动命令里传参数即可。我一般会先看一遍当前 AVD 的详细配置,再带参启动。

emulator -avd your_avd_name -dns-server 192.168.1.1 -netdelay none -netspeed full

-dns-server后面跟的 IP 会直接覆盖模拟器内部的 net.dns1 值。当你宿主机所在的局域网有内网 DNS,或者默认的 10.0.2.3 解析不了某个域名时,把这个参数改成你们公司 DNS 的 IP,通常能立刻解决问题。-netdelay none表示不加网络延迟,-netspeed full表示不限速;如果是测试弱网场景,可以改成-netdelay gprs -netspeed gsm来模拟 2G 网络。这些参数作用于模拟器进程的网络栈,比在 Android 系统里做任何设置都可靠。

请注意,这个方式不能把模拟器的 IP 改成你想要的局域网 IP。QEMU 的用户模式网络栈并不支持像 VirtualBox 那样直接“桥接网卡然后手动指定 IP”,它只会从 10.0.2.0/24 网段里分配地址。真正要解决“宿主机访问模拟器”或“模拟器访问宿主机端口”的问题,要看下面两节。

3.3 adb reverse 把宿主机 127.0.0.1 映射进模拟器

模拟器访问宿主机服务最省心的方案,不是去查宿主机局域网 IP,而是用 adb reverse。它做的是反向转发:把模拟器里的某个 TCP 端口,直接映射到宿主机的对应端口。

adb reverse tcp:8080 tcp:8080

这条命令的意思是:模拟器内部的 8080 端口收到的连接,全部原样转发到宿主机本机的 8080 端口。转发链路走 adb 通道,所以不管宿主机是 Wi-Fi 连接的 192.168.x.x,还是只监听 127.0.0.1 的本地服务,通通不用管。代码里只需要写127.0.0.1:8080,就能连上宿主机上的服务。这个做法相比把代码写死成 10.0.2.2 的优点在于:以后如果换成真机调试,真机也走 adb reverse,代码不用改。

两个tcp:8080参数,第一个是模拟器侧监听的端口,第二个是宿主机侧真实目标端口。如果两边端口不一样,也可以写成adb reverse tcp:8080 tcp:9090,效果是模拟器访问 8080 端口时,宿主机接收到的流量发往 9090。这个命令在每次模拟器冷启动后都要重新执行,所以建议把它写进一个初始化脚本里。

3.4 telnet console redir 把模拟器端口暴露给宿主机

反向的场景是:宿主机要主动访问模拟器里面跑的一个服务,比如你模拟器里开了一个 socket 服务监听在 8000 端口,宿主机想直接连过去联调。这个时候要用到控制台命令做端口重定向。

adb emu redir add tcp:8080:8000

如果模拟器版本不支持adb emu redir,可以用最通用的 telnet 方式:

telnet localhost 5554 # 登录后输入 console 控制命令,部分版本会要求 auth token redir add tcp:8080:8000

命令里冒号前是宿主机端口,冒号后是模拟器端口。执行完以后,宿主机访问127.0.0.1:8080,数据就会进入模拟器的 8000 端口。注意5554是模拟器的 console 端口,对应 adb devices 里的emulator-5554;如果你开了多个模拟器,端口会依次变成 5556、5558,需要用adb devices -l确认当前设备对应的 console 端口。telnet 登录时如果提示需要 token,token 文件在当前用户目录下的.emulator_console_auth_token里。

4. AVD IP 设置避坑:5 个最容易翻车的细节

4.1 现象:宿主机 ping 不通 10.0.2.15

我在很多次分享里都见过类似的疑问:模拟器里ifconfig明明显示 10.0.2.15,宿主机 ping 这个地址却完全不通,第一反应是模拟器网络坏了。实际不是坏,而是 QEMU 的用户模式网络栈本身就不让宿主机直接访问这个虚拟 IP。10.0.2.15 只存在于模拟器内部,宿主机上的路由表和 ARP 表里根本没有它。

解决方法是换个思路:宿主机要访问模拟器里的服务,不要 ping,也不要直接访问 10.0.2.15,用上一节的redir add tcp:8080:8000或adb forward tcp:8080 tcp:8000。如果只是验证模拟器有没有网络,直接在模拟器里 ping 10.0.2.2 或外网地址,别在宿主机侧 ping。

4.2 现象:模拟器冷启动后端口映射全都没了

前一天 adb reverse 和 redir 都配得好好的,第二天冷启动模拟器,所有端口映射都不生效。这不是配置飘了,而是 adb reverse 和 redir 都是基于当前模拟器进程的内存状态,进程退出就清空。模拟器每次冷启动都会重新初始化网络栈,之前的转发规则不会自动恢复。

解决方式很笨但有效:把所有映射命令写进一个setup_network.sh脚本里,每次冷启动后先跑脚本再开 App。脚本里可以这样组织:

adb reverse tcp:8080 tcp:8080 adb emu redir add tcp:8080:8000 adb shell getprop | grep dns

注意脚本第二行对某些模拟器版本会报unknown command,如果报错就换成 telnet redir 那套。写完脚本后,在 Android Studio 的运行配置里把这个脚本作为 before launch task 加进去,以后点运行按钮时自动执行,基本治好了我的健忘。

4.3 现象:手动设静态 IP 后过几分钟又变回 DHCP

这个和 3.1 的原因本质相同。你在 Settings 里改的是 Android 系统上层连接数据库,但 eth0 网卡的 IP 是由 QEMU 虚拟 DHCP 分配的,上层数据库一同步就会把之前的值覆盖回去。换句话说,系统自己也不知道 eth0 应该用静态 IP,你写的静态 IP 会被 Wi-Fi 配置框架的默认行为冲掉。

真的想在模拟器里给 eth0 手工绑定一个 IP,只能进 shell 用 root 权限直接改网卡:

adb root adb shell ip addr add 192.168.5.2/24 dev eth0

但这么干很容易把默认路由搞乱,除非你正在调试一个必须要固定源 IP 的网络应用,否则我不建议这么玩。更稳妥的做法是接受 10.0.2.15,所有对外依赖都通过 adb reverse 和 redir 转换。

4.4 现象:用 10.0.2.2 访问宿主机服务失败

模拟器里访问 10.0.2.2 等价于访问宿主机的 loopback 接口,这个方向是对的,但还得看宿主机的服务监听在哪个地址。如果你在宿主机跑服务时只监听了局域网 IP,比如192.168.1.100:8080,那模拟器访问 10.0.2.2:8080 自然失败,因为 10.0.2.2 映射的是 127.0.0.1,不是 192.168.1.100。

排查时先在宿主机确认监听地址,我用的是:

netstat -ano | grep 8080

看到127.0.0.1:8080或0.0.0.0:8080,模拟器才能连上;如果看到的是具体局域网 IP,就把服务启动参数里的 bind 地址改成 0.0.0.0 或 127.0.0.1。另外在 Windows 宿主机上,即使监听 0.0.0.0 也可能被防火墙拦,需要放行模拟器对应进程,这个属于宿主机侧的日常维护。

4.5 现象:App 客户端连接超时,但 adb shell 里 curl 能通

这种问题最迷惑:用 adb shell 在模拟器里curl http://10.0.2.2:8080一切正常,但 App 代码里用同样的地址连接,却一直超时或直接报 cleartext 错误。罪魁祸首通常是 Android 9 开始的明文流量限制。系统默认不允许应用使用未加密的 HTTP 流量,而 curl 是命令行工具,不受这个策略限制,所以一个通一个不通。

解决办法是在 AndroidManifest.xml 里显式允许明文流量:

<application android:usesCleartextTraffic="true" ...>

如果是只在调试环境允许,更推荐用 network security config 限制特定 IP 或域名走明文,避免正式包被安全审计扫出来。这个坑不会出现在报错堆栈里,很隐蔽,我见过不少同事卡了一个下午才找到。

5. 进阶操作:让局域网设备也连上 AVD 里的调试服务

如果只是宿主机自己访问模拟器,上面那些命令已经够了;但有时候你要拿着同一局域网里的另一台手机,去连模拟器里跑着的调试服务。常见的做法是adb forward tcp:8080 tcp:8000,它只绑定在宿主机的 loopback 上,其他设备访问不到。要让其他设备也能连,需要在宿主机上再做一次转发,把某个监听在所有网卡的端口转给127.0.0.1:8080。

在 macOS 或 Linux 上我常用 socat 完成这一步:

adb forward tcp:8080 tcp:8000 socat TCP-LISTEN:8081,bind=0.0.0.0,reuseaddr,fork TCP:127.0.0.1:8080

第一条命令让宿主机能通过 127.0.0.1:8080 访问模拟器的 8000 端口;第二条命令让宿主机在 8081 端口上接收所有网卡进来的连接,原样转发到 127.0.0.1:8080。这样局域网里的其他设备访问宿主机IP:8081,就能连上模拟器里的 8000 服务。验证时先在本机跑,再看局域网设备通不通:

curl http://127.0.0.1:8081 curl http://192.168.1.100:8081

如果第二个 curl 通,说明链路已经打通。这套组合只是解决了端口可达性,别忘了模拟器内部的 App 可能还需要允许来自外部网络的请求,也就是服务端要监听 0.0.0.0 而不是 127.0.0.1。

我自己在这个问题上翻过太多次车,后来索性把adb reverse、redir add和 socat 转发写成一段 30 行的初始化脚本,模拟器每次冷启动后跑一遍,再把curl 127.0.0.1:8081的验证命令加到脚本最后。这样再也没被模拟器的 IP 玄学坑过。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询