获取你自己的 App 所连接的服务器 IP(最常见)
这是最常见的需求,比如你正在做一个 App,需要连接一个特定的服务器,并想知道当前连接的是哪个服务器的 IP 地址。

方法 1:使用 java.net.InetAddress(推荐,适用于 HTTP/HTTPS)
如果你的 App 通过标准的 HTTP/HTTPS 协议与服务器通信(例如使用 HttpURLConnection, OkHttp, Retrofit 等),你可以通过 URL 对象解析出 IP 地址。
核心思路:
- 将你的服务器域名(如
api.example.com)构造成一个java.net.URL对象。 - 调用
URL.getHost()获取域名。 - 使用
java.net.InetAddress.getByName()方法,通过域名获取其对应的InetAddress对象。 - 最后调用
InetAddress.getHostAddress()获取 IP 地址(字符串形式)。
代码示例:
import android.os.Bundle;
import android.util.Log;
import android.widget.Button;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
// 替换成你的服务器域名
private static final String SERVER_DOMAIN = "www.baidu.com"; // 示例域名
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnGetIp = findViewById(R.id.btn_get_ip);
btnGetIp.setOnClickListener(v -> {
new Thread(() -> {
try {
// 1. 通过域名获取 InetAddress 对象
InetAddress address = InetAddress.getByName(SERVER_DOMAIN);
// 2. 获取 IP 地址
String serverIp = address.getHostAddress();
// 3. 在主线程更新 UI
runOnUiThread(() -> {
Log.d(TAG, "服务器IP地址: " + serverIp);
Toast.makeText(MainActivity.this, "服务器IP: " + serverIp, Toast.LENGTH_SHORT).show();
});
} catch (UnknownHostException e) {
e.printStackTrace();
runOnUiThread(() -> Toast.makeText(MainActivity.this, "无法解析域名", Toast.LENGTH_SHORT).show();
}
}).start();
});
}
}
注意事项:

- 网络操作:
InetAddress.getByName()是一个网络操作,会阻塞线程。必须在子线程中执行,否则会抛出NetworkOnMainThreadException异常。 - 同步阻塞:这个方法是同步的,会一直等待直到解析完成或超时,对于 UI 交互,最好使用异步方式(如
AsyncTask- 已废弃,或Kotlin Coroutines/RxJava)。 - IPv4 和 IPv6:
getHostAddress()返回的可能是 IPv4 地址(如215.177.38)或 IPv6 地址(如2408:8207:78c0:2f0a:0:ff:b08c:9a3a)。
方法 2:从已建立的 Socket 连接中获取
如果你的 App 是通过 Socket 直接与服务器通信的,可以在 Socket 连接建立后,直接从 Socket 对象中获取远程 IP 地址。
核心思路:
- 使用
Socket(String host, int port)或Socket(InetAddress address, int port)创建并建立连接。 - 连接成功后,调用
socket.getInetAddress()获取代表远程地址的InetAddress对象。 - 调用
getHostAddress()获取 IP 地址。
代码示例:
import android.os.Bundle;
import android.util.Log;
import android.widget.Button;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class SocketActivity extends AppCompatActivity {
private static final String TAG = "SocketActivity";
private static final String SERVER_DOMAIN = "www.baidu.com";
private static final int SERVER_PORT = 80; // HTTP 默认端口
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnGetSocketIp = findViewById(R.id.btn_get_socket_ip);
btnGetSocketIp.setOnClickListener(v -> {
new Thread(() -> {
try (Socket socket = new Socket(SERVER_DOMAIN, SERVER_PORT)) {
// 连接建立后,获取远程地址
InetAddress remoteAddress = socket.getInetAddress();
String serverIp = remoteAddress.getHostAddress();
runOnUiThread(() -> {
Log.d(TAG, "通过Socket获取的服务器IP: " + serverIp);
Toast.makeText(SocketActivity.this, "Socket IP: " + serverIp, Toast.LENGTH_SHORT).show();
});
} catch (UnknownHostException e) {
e.printStackTrace();
runOnUiThread(() -> Toast.makeText(SocketActivity.this, "无法解析域名", Toast.LENGTH_SHORT).show());
} catch (Exception e) {
e.printStackTrace();
runOnUiThread(() -> Toast.makeText(SocketActivity.this, "Socket连接失败", Toast.LENGTH_SHORT).show());
}
}).start();
});
}
}
优点:

- 非常直接,适用于原生 Socket 通信。
- 可以获取到连接真正建立的 IP,尤其是在使用 CDN 或负载均衡时,这个 IP 可能与
InetAddress.getByName()返回的 IP 不同。
获取局域网内另一台设备的 IP
你的 App 需要发现并连接局域网内的某个设备(如智能音箱、打印机、另一台手机等)。
方法:使用 WifiManager 进行网络扫描(需要权限)
核心思路:
- 获取
WifiManager实例。 - 获取当前连接的 Wi-Fi 的 DHCP 信息,包括网关地址。
- 扫描局域网内所有活动的设备(这会消耗较多电量)。
- 遍历扫描结果,筛选出你需要的设备(通常通过端口扫描或设备特定的通信协议来识别)。
代码示例(获取本机局域网 IP):
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.Button;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Collections;
import java.util.List;
public class LanIpActivity extends AppCompatActivity {
private static final String TAG = "LanIpActivity";
private static final int REQUEST_CODE_LOCATION = 101;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnGetLanIp = findViewById(R.id.btn_get_lan_ip);
btnGetLanIp.setOnClickListener(v -> {
// 从 Android 6.0 开始,需要位置权限才能获取 Wi-Fi 信息
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_CODE_LOCATION);
return;
}
String localIp = getLocalIpAddress();
Toast.makeText(this, "本机局域网IP: " + localIp, Toast.LENGTH_SHORT).show();
Log.d(TAG, "本机局域网IP: " + localIp);
});
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CODE_LOCATION) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 权限已授予,可以重新执行操作
String localIp = getLocalIpAddress();
Toast.makeText(this, "本机局域网IP: " + localIp, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "需要位置权限才能获取IP", Toast.LENGTH_SHORT).show();
}
}
}
/**
* 获取本机局域网 IP 地址
*/
private String getLocalIpAddress() {
WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
if (wifiManager != null) {
WifiInfo info = wifiManager.getConnectionInfo();
int ipAddress = info.getIpAddress();
return ((ipAddress & 0xFF) + "." +
(ipAddress >> 8 & 0xFF) + "." +
(ipAddress >> 16 & 0xFF) + "." +
(ipAddress >> 24 & 0xFF));
}
return null;
}
/**
* 另一种获取本机IP的方法(更通用,也适用于移动数据)
*/
private String getLocalIpAddressByNetworkInterface() {
try {
List<NetworkInterface> networkInterfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
for (NetworkInterface ni : networkInterfaces) {
List<InetAddress> inetAddresses = Collections.list(ni.getInetAddresses());
for (InetAddress address : inetAddresses) {
if (!address.isLoopbackAddress()) {
String hostAddress = address.getHostAddress();
// 过滤掉 IPv6 地址
if (hostAddress.indexOf(':') < 0) {
return hostAddress;
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
重要提醒:
- 权限:从 Android 6.0 (API 23) 开始,获取 Wi-Fi 信息需要
ACCESS_FINE_LOCATION权限,因为它会泄露物理位置信息。 - 扫描局域网设备:扫描整个局域网 (
WifiManager.startScan()+WifiManager.getScanResults()) 是一个耗电且耗时的操作,应谨慎使用,更现代的方案是使用 mDNS (Multicast DNS) 或 Bonjour 协议,设备可以广播自己的存在,其他设备可以发现它,无需主动扫描,Android 10+ 提供了NsdManager(Network Service Discovery) 来支持 mDNS。
获取 App 访问过的所有服务器 IP(高级/不推荐)
这个需求比较特殊,比如你想监控 App 的所有网络活动。这通常涉及用户隐私,并且可能会被应用商店拒绝。
方法:使用 VpnService 创建本地 VPN
这是唯一能在应用层拦截所有网络流量的方法,你的 App 会作为一个 VPN 服务,所有网络请求都会先经过你的 App,然后你再转发出去,在这个过程中,你可以记录下所有访问的目标 IP。
核心思路:
- 创建一个继承自
VpnService的服务。 - 在
VpnService中,建立一个FileDescriptor,将其设置为系统的 VPN 网关接口。 - 创建一个线程,从这个
FileDescriptor中读取所有外发的网络数据包。 - 解析数据包(通常是 IP 包),提取出目标 IP 地址。
- 将数据包再转发到真实的网络接口。
这是一个非常复杂且高级的主题,通常用于网络安全工具、代理或流量监控 App。 普通应用强烈不建议使用此方法。
总结与最佳实践
| 场景 | 推荐方法 | 关键 API/技术 | 注意事项 |
|---|---|---|---|
| 获取自己连接的服务器IP | InetAddress.getByName() |
java.net.URL, java.net.InetAddress |
必须在子线程执行,同步阻塞。 |
| 通过Socket获取服务器IP | Socket.getInetAddress() |
java.net.Socket, InetAddress |
最直接,适用于原生Socket通信。 |
| 获取本机局域网IP | WifiManager |
WifiManager, WifiInfo |
需要 ACCESS_FINE_LOCATION 权限。 |
| 发现局域网内其他设备 | mDNS / NsdManager | android.net.nsd.NsdManager |
推荐方案,比扫描更高效、省电。 |
| 监控所有网络访问 | VpnService |
android.net.VpnService |
高级、复杂、涉及隐私,不常用。 |
对于绝大多数开发者来说,场景一中的两种方法已经足够满足需求,请根据你的网络通信方式(HTTP 还是 Socket)来选择合适的实现。
