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

Android和IPv6上Java套接字的奇怪行为,android,okhttp,android-networking,Android,Okhttp,Android Networking,我有一些使用套接字的代码。简单的东西,比如: Socket socket = new Socket(); InetSocketAddress endpoint = new InetSocketAddress(host, port); socket.connect(endpoint, 120000); 对于某些web地址,它将冻结直到超时,但仅限于我的一些用户。我最终通过让用户向我发送日志来跟踪它,当endpoint是IPv6地址时,问题就会发生。因此,我想澄清一下,如果一个网址没有IPv6记录

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

Socket socket = new Socket();
InetSocketAddress endpoint = new InetSocketAddress(host, port);
socket.connect(endpoint, 120000);
对于某些web地址,它将冻结直到超时,但仅限于我的一些用户。我最终通过让用户向我发送日志来跟踪它,当
endpoint
是IPv6地址时,问题就会发生。因此,我想澄清一下,如果一个网址没有IPv6记录,那么它只适用于那些有问题的用户。但如果该网址有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);
        ......
Socket套接字=新套接字();
InetAddress=InetAddress.getByName(主机);
if(Inet6Address的地址实例){
Log.w(标记,“找到ipv6地址,查找ipv4”+地址);
InetAddress[]inetAddressArray=InetAddress.getAllByName(主机);
对于(int i=0;i

本质上,如果
InetAddress,我会强制套接字使用IPv4地址。getByName(主机)
返回IPv6地址,并且IPv4可用。我对此有点紧张,因此我仍然希望有人有更好的解决方案

“对于某些主机,它将冻结直到超时,但仅限于我的一些用户。我最终通过让用户向我发送日志来跟踪它,问题发生在
endpoint.getAddress()
是IPv6地址时。”在某种程度上,它挂起了吗?问题是什么“更详细地说,它在
connect
方法上超时。我得到一个
SocketTimeoutException
异常。它过去只是挂起,因为我是通过执行
new socket(host,port)
创建套接字的,但现在我使用
new socket()
后跟
connect()
有一个超时。我有超过250万次下载,而且我可能每隔一周收到一封关于这个问题的电子邮件。因此,这个问题并不普遍,但确实发生了。尝试这些解决方案,而不是使用ipadress直接将它们映射到域地址并使用。我不知道这是否对你有帮助。所谓“冻结”,你的意思是你得到了一个套接字连接超时例外n?我已经有一段时间没有研究这个问题了,但我认为它会超时,但只对一些人和启用ipv6的人。