2

大家好,我已经为此苦苦挣扎了一段时间,找不到解决方案。

在java中,这段代码有效:

InetAddress serverAddr = InetAddress.getByName("myservice.local");
Socket socket = new Socket(serverAddr,  PoolServerAddress.DEFAULT_PORT);

在android中同样不起作用。我尝试删除“.local”并在清单中添加所有必要的权限:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />

我也尝试在执行该代码之前添加多播锁定,但没有办法解决这个问题。

我得到以下异常:

06-03 13:18:14.438: W/System.err(31636): java.net.UnknownHostException: Unable to    

resolve host <server_name>: No address associated with hostname

06-03 13:18:14.438: W/System.err(31636):    at 

java.net.InetAddress.lookupHostByName(InetAddress.java:434)

06-03 13:18:14.438: W/System.err(31636):    at 

java.net.InetAddress.getAllByNameImpl(InetAddress.java:239)

06-03 13:18:14.438: W/System.err(31636):    at    

java.net.InetAddress.getByName(InetAddress.java:292)

06-03 13:18:14.438: W/System.err(31636):    at 

com.example.jelly_test.MainActivity.connect(MainActivity.java:113)

06-03 13:18:14.438: W/System.err(31636):    at      

com.example.jelly_test.MainActivity$ResolvingThread.run(MainActivity.java:71)

06-03 13:18:14.438: W/System.err(31636): Caused by: libcore.io.GaiException:     

getaddrinfo 

failed: EAI_NODATA (No address associated with hostname)

06-03 13:18:14.438: W/System.err(31636):    at libcore.io.Posix.getaddrinfo(Native 

Method)

06-03 13:18:14.438: W/System.err(31636):    at 

libcore.io.ForwardingOs.getaddrinfo(ForwardingOs.java:55)

06-03 13:18:14.438: W/System.err(31636):    at 

java.net.InetAddress.lookupHostByName(InetAddress.java:415)

06-03 13:18:14.438: W/System.err(31636):    ... 4 mor

如果我提供 ip 而不是 service 它可以工作,但我需要能够提供名称。此外,我尝试添加JmDNS将名称解析为 ip,但速度很慢,仅适用于办公室的内部服务,但我们的一些服务在网络外部,但它们仍然可以通过 java 版本访问,但不能通过 android 访问。还有什么我可以尝试的吗?非常感谢,因为我的想法已经用完了......!

编辑:我认为我的问题是由于 android 中有一个错误,它只接受FQDN,例如:myservice.company.com

4

1 回答 1

0

根据这里的要求,我发现可以临时解决此问题的选项,因为即使在最新的 Android 版本(撰写本文时为 4.4)中,该错误仍未得到修复。

确保将问题中指示的所有必需权限添加到清单中。

选项 1:使用 JmDNS 库来发现可用服务器列表并找到你的,如果你不知道这里是一个很好的教程: http ://home.heeere.com/tech-androidjmdns.html 这种方法很慢而且我发现有些服务没有显示(他们必须用 zeroconf 做广告)

选项 2:要求您的用户输入完全限定的域名,例如 name.comany.com 而不是 name.local

选项 3:这确实是一个 hack,但如果您知道 FQDN 的类型为 someName.myComp.com 并且用户输入了 someName.local,您必须删除“.local”并尝试猜测域是什么:

private String getTargetIp(String host) {

    System.out.println("Will try to create socket with "+host);

    MulticastLock multicastLock = null;
    String ipToReturn = null;
    Socket socket = null;
    try {

        WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
        multicastLock = wifiManager.createMulticastLock("any_name");
        multicastLock.acquire();
        DhcpInfo info = wifiManager.getDhcpInfo();

        int ip = info.ipAddress;
        InetAddress local = getInetAddress(ip);
        String localHostName = local.getCanonicalHostName();
        Log.d(TAG, "Device ip addr1 = "+local +" name= "+localHostName);
        String[] temp = localHostName.split("\\.");

        //replace the first part with our name and obtain FQDN
        String targetFullHostName=localHostName.replace(temp[0], host);
        Log.d(TAG, "targetFullHostName = "+targetFullHostName);

        //this is not mandatory but here we are trying to retrieve the ip address
        //it maybe also a way to check if we guessed right
        InetAddress serverAddr = InetAddress
                .getByName(targetFullHostName);
        socket = new Socket(serverAddr,
                PoolServerAddress.DEFAULT_PORT);
        ipToReturn = socket.getInetAddress().getHostAddress();

        Log.d(TAG, "socket remote address=" + ipToReturn);

    } catch (UnknownHostException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }catch(Exception e){
        Log.e(TAG, "Other Exception");
    }

    finally {
        if (multicastLock != null)
            multicastLock.release();

        if(socket!=null)
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
    }
    return ipToReturn;

}

选项 4:从 api 级别 16 开始,您可以使用 Android Service Discovery 侦听器列出可用服务并找到您要查找的服务。这与 JmDNS 的工作方式类似:您发现所有服务并尝试在列表中找到您的服务。这是文档的链接:http: //developer.android.com/training/connect-devices-wireless/nsd.html#discover

于 2014-01-22T18:55:00.517 回答