admin管理员组文章数量:1654378
问题描述
开发的是一款安卓嵌入式设备,设备硬件限制只能链接WiFi,测试场景或者展会场景只能链接手机热点、路由器盒子开放的wifi。
经过同事反馈,手机4G网开放的热点网络请求特别慢,卡了快30s左右,之后网络请求就正常了,但是项目杀掉,重新打开,又卡了30s左右,问题反馈过来一脸懵逼状态,从来没有遇到过这种情况,然而手边所有测试机都属于正常现象,于是开始研究什么问题造成的。
问题分析
目前发现部分手机出现网络请求慢问题(小米手机),但是一般手机都属于正常
于是使用以下代码 DNS 解析的 IP 地址
try {
InetAddress[] mInetAddresses= InetAddress.getAllByName("xxxx");
for(InetAddress address: mInetAddresses){
System.out.println(address.getHostAddress());
}
} catch (UnknownHostException e) {
e.printStackTrace();
}
发现
1、连接到配置公网的路由器wifi,只解析到 ipv4 地址
2、连接到4G开放的热点网,解析到了ipv4、ipv6俩个地址
思考:
但是ipv6默认为集合中的第一个,是否我们可以尝试修改集合第一个为ipv4呢?
辅助阅读资料
网上查了查,答案都指向了DNS解析设置的问题,解析有两种 ipv4 ipv6 ,android默认不支持ipv6解析,之后问了下后台配置,说IOS 的 appstore 审核,必须需要ipv6的配置才能正常进行,所以服务端增加了 ipv6 支持,同时也支持ipv4,但是ipv6的入口再美国,那这样看来,猜测是否是android手机默认通过ipv6去连接后端服务器,绕了一大圈才返回结果?于是,各个问题都分别科普下。
1、android为何不支持ipv6解析
IPv4地址即将枯竭,这种警告已经发出了一次又一次,但是IPv6依然迟迟无法普及,原因之一就是有些巨头不提供支持。
Windows、Linux、Mac OS X、iOS等系统都已经支持了IPv6,但是Google Android却迟迟不肯加入。要知道,Android设备的规模已达几十亿,占据了智能手机市场的几乎八成,它不支持IPv6无疑是极大的桎梏。
由于不支持新的IP地址动态分配协议DHCPv6,Android设备在无线网络中经常处于不利地位,这也让很多网络管理人员很郁闷。为此,不少公司甚至禁止在企业网络中使用Android设备,这也给他们的IPv6部署产生了很大的阻碍。
不少专业人士对Google的迟缓感到十分不满,尤其是在Google Code的一个帖子中,很多人甚至愤怒得破口大骂。
不过在Google开发者、IPv6权威专家Lorenzo Colliti看来,Android不支持IPv6也是有苦衷的,比如会影响那些依赖IPv4的应用,无法强制开发者采用IPv6网络地址,地址转换后性能会有损失等等。
2、为何要支持ipv6
苹果公司的App审核人员进行审核时,由于国内大部分开发者的服务器不支持IPv6-Only访问,因此只能通过苹果公司自己的NAT64+DNS64服务器进行测试,如果苹果的服务器不能有效的给AppServer返回一个IPv6地址,就会导致无法访问等问题。其结果便是审核失败,App被拒。
问题解决
自定义okhttp中dns解析,查看了下okhttp开放了自定义dns方法,于是追踪到源码可以看到
package okhttp3;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.List;
/**
* A domain name service that resolves IP addresses for host names. Most applications will use the
* {@linkplain #SYSTEM system DNS service}, which is the default. Some applications may provide
* their own implementation to use a different DNS server, to prefer IPv6 addresses, to prefer IPv4
* addresses, or to force a specific known IP address.
*
* <p>Implementations of this interface must be safe for concurrent use.
*/
public interface Dns {
/**
* A DNS that uses {@link InetAddress#getAllByName} to ask the underlying operating system to
* lookup IP addresses. Most custom {@link Dns} implementations should delegate to this instance.
*/
Dns SYSTEM = new Dns() {
@Override public List<InetAddress> lookup(String hostname) throws UnknownHostException {
if (hostname == null) throw new UnknownHostException("hostname == null");
try {
return Arrays.asList(InetAddress.getAllByName(hostname));
} catch (NullPointerException e) {
UnknownHostException unknownHostException =
new UnknownHostException("Broken system behaviour for dns lookup of " + hostname);
unknownHostException.initCause(e);
throw unknownHostException;
}
}
};
/**
* Returns the IP addresses of {@code hostname}, in the order they will be attempted by OkHttp. If
* a connection to an address fails, OkHttp will retry the connection with the next address until
* either a connection is made, the set of IP addresses is exhausted, or a limit is exceeded.
*/
List<InetAddress> lookup(String hostname) throws UnknownHostException;
}
于是我们的解决思路是,调换集合中ipv4 ipv6位置,将ipv4当到集合首位
import okhttp3.Dns;
/**
* File descripition:
*
* @author lp
* @date 2019/4/16
*/
public class ApiDns implements Dns {
@Override
public List<InetAddress> lookup(String hostname) throws UnknownHostException {
if (hostname == null) {
throw new UnknownHostException("hostname == null");
} else {
try {
List<InetAddress> mInetAddressesList = new ArrayList<>();
InetAddress[] mInetAddresses = InetAddress.getAllByName(hostname);
for (InetAddress address : mInetAddresses) {
if (address instanceof Inet4Address) {
mInetAddressesList.add(0, address);
} else {
mInetAddressesList.add(address);
}
}
return mInetAddressesList;
} catch (NullPointerException var4) {
UnknownHostException unknownHostException = new UnknownHostException("Broken system behaviour");
unknownHostException.initCause(var4);
throw unknownHostException;
}
}
}
}
将自定义方法插入到okhttp中
OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
ClearableCookieJar cookieJar =
new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(AppUMS.mContent));
httpClientBuilder
.cookieJar(cookieJar)
.addInterceptor(interceptor)
.addInterceptor(new HeadUrlInterceptor())
//设置请求超时时长
.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)//错误重联
.dns(new ApiDns());
版权声明:本文标题:Android 链接4G热点网络第一次请求很慢ipv6地址链接异常分析及解决 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/xitong/1729641915a1208559.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论