凌峰创科服务平台

Android如何获取服务器IP地址?

获取你自己的 App 所连接的服务器 IP(最常见)

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

Android如何获取服务器IP地址?-图1
(图片来源网络,侵删)

方法 1:使用 java.net.InetAddress(推荐,适用于 HTTP/HTTPS)

如果你的 App 通过标准的 HTTP/HTTPS 协议与服务器通信(例如使用 HttpURLConnection, OkHttp, Retrofit 等),你可以通过 URL 对象解析出 IP 地址。

核心思路:

  1. 将你的服务器域名(如 api.example.com)构造成一个 java.net.URL 对象。
  2. 调用 URL.getHost() 获取域名。
  3. 使用 java.net.InetAddress.getByName() 方法,通过域名获取其对应的 InetAddress 对象。
  4. 最后调用 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();
        });
    }
}

注意事项:

Android如何获取服务器IP地址?-图2
(图片来源网络,侵删)
  • 网络操作InetAddress.getByName() 是一个网络操作,会阻塞线程。必须在子线程中执行,否则会抛出 NetworkOnMainThreadException 异常。
  • 同步阻塞:这个方法是同步的,会一直等待直到解析完成或超时,对于 UI 交互,最好使用异步方式(如 AsyncTask - 已废弃,或 Kotlin Coroutines/RxJava)。
  • IPv4 和 IPv6getHostAddress() 返回的可能是 IPv4 地址(如 215.177.38)或 IPv6 地址(如 2408:8207:78c0:2f0a:0:ff:b08c:9a3a)。

方法 2:从已建立的 Socket 连接中获取

如果你的 App 是通过 Socket 直接与服务器通信的,可以在 Socket 连接建立后,直接从 Socket 对象中获取远程 IP 地址。

核心思路:

  1. 使用 Socket(String host, int port)Socket(InetAddress address, int port) 创建并建立连接。
  2. 连接成功后,调用 socket.getInetAddress() 获取代表远程地址的 InetAddress 对象。
  3. 调用 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();
        });
    }
}

优点

Android如何获取服务器IP地址?-图3
(图片来源网络,侵删)
  • 非常直接,适用于原生 Socket 通信。
  • 可以获取到连接真正建立的 IP,尤其是在使用 CDN 或负载均衡时,这个 IP 可能与 InetAddress.getByName() 返回的 IP 不同。

获取局域网内另一台设备的 IP

你的 App 需要发现并连接局域网内的某个设备(如智能音箱、打印机、另一台手机等)。

方法:使用 WifiManager 进行网络扫描(需要权限)

核心思路:

  1. 获取 WifiManager 实例。
  2. 获取当前连接的 Wi-Fi 的 DHCP 信息,包括网关地址。
  3. 扫描局域网内所有活动的设备(这会消耗较多电量)。
  4. 遍历扫描结果,筛选出你需要的设备(通常通过端口扫描或设备特定的通信协议来识别)。

代码示例(获取本机局域网 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。

核心思路:

  1. 创建一个继承自 VpnService 的服务。
  2. VpnService 中,建立一个 FileDescriptor,将其设置为系统的 VPN 网关接口。
  3. 创建一个线程,从这个 FileDescriptor 中读取所有外发的网络数据包。
  4. 解析数据包(通常是 IP 包),提取出目标 IP 地址。
  5. 将数据包再转发到真实的网络接口。

这是一个非常复杂且高级的主题,通常用于网络安全工具、代理或流量监控 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)来选择合适的实现。

分享:
扫描分享到社交APP
上一篇
下一篇