【问题标题】:Java application getting different IP from android application - Why?Java 应用程序从 android 应用程序获得不同的 IP - 为什么?
【发布时间】:2014-05-16 03:26:51
【问题描述】:

我制作了一个需要连接一个由 wamp 服务器提供的本地数据库的 android 应用程序。首先使用android虚拟设备(AVD)我的IP第一次连接服务器曾经是:10.0.2.2。我的 AVD 连接正常,但是当我尝试在我的设备上直接连接时,他没有找到具有此 10.0.2.2 IP 的本地服务器。此时,我已将 IP 更改为 192.168.1.5,这是我的 LAN 电缆 IP,设备和 AVD 都运行没有问题……但有时我需要更改与 wifi 的连接,这会更改 IP ..另外,我意识到在我的源代码中修复一个 IP 将是发布 android 应用程序的问题,因为其他人将拥有其他 LAN IP 地址。

为了解决这个问题,我开始寻找解决方案,比如动态获取局域网IP。为此,我构建了这个 Java 应用程序作为测试:

public class test {
    public static void main(String[] args) throws Exception
    {
        String roundHost = null;
        Enumeration<NetworkInterface> n = NetworkInterface.getNetworkInterfaces();
        for (; n.hasMoreElements();)
        {
            NetworkInterface e = n.nextElement();

            Enumeration<InetAddress> a = e.getInetAddresses();
            for (; a.hasMoreElements();)
            {
                InetAddress addr = a.nextElement();
                if (addr.isSiteLocalAddress()){
                    String pureHost = addr.getByName(addr.getHostName()).toString();
                    roundHost = addr.getHostAddress();
                    pureHost = pureHost.substring(addr.getHostName().length()+1);

                    if(!roundHost.equals(pureHost))
                        break;
                }
            }
        }
        System.out.println(roundHost);
    }
}

作为输出,这个 java 应用程序为我提供了正确的 LAN wifi IP,甚至是我的 LAN 电缆 IP,即 192.168.1.3192.168.1.7。从这里我制作了一个“IPParser”以在我的 android 应用上使用:

public class IPParser {

    String pureHost, roundHost = null;

    public IPParser() throws UnknownHostException{

        Enumeration<NetworkInterface> n = null;
        try {
            n = NetworkInterface.getNetworkInterfaces();
        } catch (SocketException e1) {
            e1.printStackTrace();
        }
        for (; n.hasMoreElements();)
        {
            NetworkInterface e = n.nextElement();

            Enumeration<InetAddress> a = e.getInetAddresses();
            for (; a.hasMoreElements();)
            {
                InetAddress addr = a.nextElement();
                if (addr.isSiteLocalAddress()){
                    pureHost = addr.getByName(addr.getHostName()).toString();
                    roundHost = addr.getHostAddress();
                    pureHost = pureHost.substring(addr.getHostName().length()+1);

                    if(!roundHost.equals(pureHost))
                        break;
                }
            }
        }
     }

     public String returnIp() {
         return roundHost;
     }
}

如您所见,它非常相似;不同之处只是一些结构更改以适应所需的语法。现在真正的问题来了:当我尝试在我的 AVD 中运行这个解析器时,我的 ip 是 10.0.2.15 并直接在我的设备中运行,ip 返回是 192.168.1.6 - 显然 android 应用程序崩溃了,因为它找不到要连接的本地服务器。

我的 IP 配置信息:

我不是网络专家,所以我问,放轻松,如果我说技术上的错误或相邻的内容,请编辑并纠正我..最后我问:

为什么会发生这种情况以及如何解决这个问题?

【问题讨论】:

  • 如果服务器是本地的,为什么不能只使用 127.0.0.1?
  • 根本不起作用(127.0.0.1);应用程序崩溃:stackoverflow.com/questions/5806220/…;我对此进行了大量研究..考虑到变量的数量(使用 AVD、使用真实设备、其他人的 wifi),它不太可能修复 ip...
  • 我误解了,我假设当您说“在本地运行”时,您的意思是在设备上本地运行。如果您在网络内的计算机上运行该服务,您需要另一个进程来解决它,可能是一个可公开访问的 IP 地址?

标签: java android networking ip localhost


【解决方案1】:

您提到的 IP(10.0.2.2192.168.1.5)来自两个不同的网络,这是有道理的,因为 documentation 声明:

模拟器的每个实例都在虚拟路由器/防火墙后面运行 将其与您的开发机器的网络隔离的服务 界面和设置以及来自互联网。模拟设备可以 看不到您的开发机器或其他模拟器实例 网络。相反,它只看到它是通过以太网连接的 到路由器/防火墙。

每个实例的虚拟路由器管理 10.0.2/24 网络 地址空间——路由器管理的所有地址都采用以下形式 10.0.2.,数字在哪里。该空间内的地址由模拟器/路由器预先分配如下:

这意味着当使用 AVD 时,会创建一个虚拟网络,设备和计算机都是其中的一部分。在您的情况下,您的本地计算机在此虚拟网络中使用地址 10.0.2.2 和 AVD 10.0.2.15。但是当您直接通过设备连接时,计算机的 IP(以及设备的 IP)在 LAN 的地址空间中(即192.168.1.5192.168.1.6)。

您发布的代码解析了主机的IP地址,但是如果您希望设备自动解析服务器的IP地址并且您可以保证它们始终连接到同一个局域网,那么您可以使用多播 UDP 消息(我没有找到真正好的来源,但您可以开始 hereherehere)。这种类型的通信将 UDP 数据报发送到网络到特定的多播 IP 地址和端口,网络中的其他设备正在侦听该地址和端口。我在一个需要在网络中查找计算机的 Android 应用程序中使用了这个方案,所以我知道它可以工作。如果需要,我可以分享一些代码。


编辑

以下 sn-ps 代码是实现网络中计算机搜索的代码。用于此的 Android 应用程序可以控制网络中运行服务器应用程序的任何计算机的鼠标和键盘。

Android 客户端

public void findComputers(View v) {
    try {
        int port = 4444;
        String multicastAddr = "224.168.1.0";

        DatagramSocket socket = new DatagramSocket(port);
        socket.setSoTimeout(300);
        InetAddress group = InetAddress
                .getByName(multicastAddr);
        DatagramPacket packet = new DatagramPacket(new byte[] { 1 }, 1,
                group, port);
        socket.send(packet);

        // Give time to the servers to respond
        Thread.sleep(100);

        while (true) {
            try {
                // Listen for the servers responses
                byte[] buffer = new byte[256];
                packet = new DatagramPacket(buffer, buffer.length);
                socket.receive(packet);
                String data = new String(packet.getData());
                // Information sent from servers include the host's name
                // and IP addres separated by a semicolon.
                String[] parts = data.split(";");

                // Add a server to the result list.
                Computer computer = new Computer(parts[1].trim(),
                        parts[0].trim());
                this.computers.put(computer.getName(), computer);
            } catch (InterruptedIOException ex) {
                break;
            }
        }
        socket.close();
    } catch (SocketException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    String output = "No computers found.";

    if (this.computers.size() > 0) {
        output = this.computers.size() + " computer(s) found.";
        this.fillComputers();
    }

    Toast.makeText(this, output, Toast.LENGTH_SHORT).show();
}

服务器

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;

/**
 * Receives UDP broadcast packets in the default port requesting for server name
 * and IP, broadcasting the information in return.
 * 
 * @author jfacorro
 * 
 */
public class NameResolverService extends Thread {

    private InetAddress localAddress = null;
    private byte[] localAddressData = null;
    private MulticastSocket socket = null;
    private boolean exit = false;

    public NameResolverService() {
    }

    public void exit() {
        this.exit = true;
        this.socket.close();
    }

    @Override
    public void run() {
        try {
            int port = 4444;
            String multicastAddr = "224.168.1.0";

            // Get current address
            this.localAddress = InetAddress.getLocalHost();

            this.socket = new MulticastSocket(port);
            InetAddress group = InetAddress.getByName(multicastAddr);
            this.socket.joinGroup(group);
            this.localAddressData = (this.localAddress.getHostAddress() + ";" + this.localAddress
                    .getHostName()).getBytes();

        } catch (IOException ex) {
            this.notified.notified(ex.getMessage());
            ex.printStackTrace();
        }

        while (!this.exit) {
            try {
                byte[] buffer = new byte[1];
                DatagramPacket packet = new DatagramPacket(buffer,
                        buffer.length);

                socket.receive(packet);

                InetAddress address = packet.getAddress();
                int port = packet.getPort();
                packet = new DatagramPacket(this.localAddressData,
                        this.localAddressData.length, address, port);

                socket.send(packet);

            } catch (IOException e) {
                if(!this.exit)
                    e.printStackTrace();
            }
        }

        this.socket.close();
    }
}

【讨论】:

  • 尽可能分享代码,这对我和其他程序员来说都很棒。感谢支持;)
  • 我刚刚添加了我在服务器和Android客户端中使用的代码。希望对您有所帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-24
  • 1970-01-01
  • 2015-10-01
相关资源
最近更新 更多