Android和IPv6上使用Java套接字的奇怪行为

时间:2017-05-13 15:55:50

标签: android okhttp android-networking

我有一些使用套接字的代码。简单的东西,如:

Socket socket = new Socket();
InetSocketAddress endpoint = new InetSocketAddress(host, port);
socket.connect(endpoint, 120000);

对于某些网址,它会冻结,直到超时,但仅限部分用户使用。我最终通过让用户向我发送日志来跟踪它,当endpoint是IPv6地址时会出现问题。所以,只是为了澄清,如果一个网址没有IPv6记录,那么它将适用于那些有问题的用户。但是,如果Web地址具有IPv6记录,那么这些用户将超时。所有其他用户(包括我自己)都没有问题。

奇怪的是,如果我使用OkHttp,这个问题就不会发生。此外,如果用户只是在手机上使用Chrome加载页面,则问题不会发生。我知道较新的Android版本使用OkHttp进行HttpUrlConnection,这可能就是原因。

我已经使用以下方法为某些用户修复了它:

java.lang.System.setProperty("java.net.preferIPv4Stack", "true");
java.lang.System.setProperty("java.net.preferIPv6Addresses", "false");

但对其他用户来说甚至没有帮助。

我试图理解为什么这甚至是一个问题,为什么只为少数用户?为什么在某些手机上系统属性会修复它,而在其他手机上却会被忽略。

编辑:我找到了系统属性无法解决问题的用户的已确认解决方案。

基本上我的代码是:

Socket socket = new Socket();
InetSocketAddress endpoint = new InetSocketAddress(host, port);
try{
    socket.connect(endpoint, 120000);
    ....

现在是:

    Socket socket = new Socket();
    InetAddress address = InetAddress.getByName(host);
    if (address instanceof Inet6Address) {
        Log.w(TAG, "Found ipv6 address, looking for ipv4 " + address);
        InetAddress[] inetAddressArray = InetAddress.getAllByName(host);
        for (int i = 0; i < inetAddressArray.length; i++) {
            if (inetAddressArray[i] instanceof Inet4Address) {
                address = inetAddressArray[i];
                Log.w(TAG, "Found ipv4 " + address);
                break;
            }
        }
    }
    InetSocketAddress endpoint = new InetSocketAddress(address, port);
    //InetSocketAddress endpoint = new InetSocketAddress(host, port);
    try {
        socket.connect(endpoint, 120000);
        ......

基本上,如果InetAddress.getByName(host)返回IPv6地址并且IPv4可用,我强制套接字使用IPv4地址。我这样做有点紧张,所以如果有人有更好的解决方案,我仍然会更喜欢。

0 个答案:

没有答案