我有一些使用套接字的代码。简单的东西,如:
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地址。我这样做有点紧张,所以如果有人有更好的解决方案,我仍然会更喜欢。