Android 4.4.4 -Andoird 5.0.0代理(ProxySlector 中select函数)导致的BUG分析
来源:互联网 发布:surge是什么软件 编辑:程序博客网 时间:2024/06/07 00:16
Android 4.4.4 发展到 Andoird 5.0.0 其中 OKhttp 中的一点点变化,导致的一个问题:在使用PRoxySelector 中的select函数返回proxy ,构造proxy如果使用的resolve的方式构造,在而后的网络请求中会经历如下过程:1、host 解析成 InetAddress2、InetAddress反向解析成name3、然后将name正向解析成InetAddress过程及其繁琐,导致请求的效率下降,也可能导致错误。什么样的错误呢?例如先给ip:1、1.2.3.4,2、逆向解析成 :4.3.2.1.broad.wh.hb.dynamic.163data.com.cn3、正向解析出错 public1.114dns.com can't find 4.3.2.1.broad.wh.hb.dynamic.163data.com.cn: Non-existent domain仔细分析原因后发现,Android 5.0.0以下的网络请求使用OKhttp,然后里面有一个比较关键的类RouteSelector。其中有一段代码是这样的:
212
private void resetNextInetSocketAddress(Proxy proxy) throws UnknownHostException {
213
socketAddresses = null; // Clear the addresses. Necessary if getAllByName() below throws!
214
215
String socketHost;
216
if (proxy.type() == Proxy.Type.DIRECT) {
217
socketHost = uri.getHost();
218
socketPort = getEffectivePort(uri);
219
} else {
220
SocketAddress proxyAddress = proxy.address();
221
if (!(proxyAddress instanceof InetSocketAddress)) {
222
throw new IllegalArgumentException(
223
"Proxy.address() is not an " + "InetSocketAddress: " + proxyAddress.getClass());
224
}
225
InetSocketAddress proxySocketAddress = (InetSocketAddress) proxyAddress;
226
socketHost = proxySocketAddress.getHostName();
227
socketPort = proxySocketAddress.getPort();
228
}
229
230
// Try each address for best behavior in mixed IPv4/IPv6 environments.
231
socketAddresses = dns.getAllByName(socketHost);
232
nextSocketAddressIndex = 0;
233
}
publicclassInetAddressimplementsSerializable {
privatestaticInetAddress getHostByAddrImpl(InetAddress address)throwsUnknownHostException {
BlockGuard.getThreadPolicy().onNetwork();
try{
String hostname = Libcore.os.getnameinfo(address, NI_NAMEREQD);//如果找不到主机名字, 将其作为一个错误对待.
returnmakeInetAddress(address.ipaddress.clone(), hostname);
}catch(GaiException gaiException) {
throwgaiException.rethrowAsUnknownHostException();
}
}
publicString getHostName() {
if(hostName==null) {
try{
hostName=getHostByAddrImpl(this).hostName;
}catch(UnknownHostException ex) {
hostName= getHostAddress();
}
}
returnhostName;
}
/**
* Returns the numeric representation of this IP address (such as "127.0.0.1").
*/
publicString getHostAddress() {
returnLibcore.os.getnameinfo(this, NI_NUMERICHOST); // Can't throw.以数字形式而非名字返回主机地址
}
}
- NI_DGRAM: 服务基于数据报而非基于流.
- NI_NAMEREQD: 如果找不到主机名字, 将其作为一个错误对待.
- NI_NOFQDN: 对于本地主机, 仅返回完全限定域名的节点名部分.
- NI_NUMERICHOST: 以数字形式而非名字返回主机地址.
- NI_NUMERICSERV: 以数字形式而非名字返回服务地址(即端口号).
其中代码段:
226
socketHost = proxySocketAddress.getHostName();
获取到的结果会是一个通过逆向解析获取ip对应的域名,如果找不到主机名字, 将其作为一个异常抛出.然后使用IP作为host。
按照正常逻辑 从IP反向解析域名能通的话,应该这个域名也能够解析成IP!!!
但是现实生活中不是这样的,可能我们活在中国奇葩的网络中吧。
还好在Andorid 5.0.0以后版本中的OKhttp使用已经切换如下代码了:
245
private void resetNextInetSocketAddress(Proxy proxy) throws UnknownHostException {
246
// Clear the addresses. Necessary if getAllByName() below throws!
247
inetSocketAddresses = new ArrayList<>();
248
249
String socketHost;
250
int socketPort;
251
if (proxy.type() == Proxy.Type.DIRECT || proxy.type() == Proxy.Type.SOCKS) {
252
socketHost = address.getUriHost();
253
socketPort = getEffectivePort(uri);
254
} else {
255
SocketAddress proxyAddress = proxy.address();
256
if (!(proxyAddress instanceof InetSocketAddress)) {
257
throw new IllegalArgumentException(
258
"Proxy.address() is not an " + "InetSocketAddress: " + proxyAddress.getClass());
259
}
260
InetSocketAddress proxySocketAddress = (InetSocketAddress) proxyAddress;
261
socketHost = getHostString(proxySocketAddress);
262
socketPort = proxySocketAddress.getPort();
263
}
264
265
// Try each address for best behavior in mixed IPv4/IPv6 environments.
266
for (InetAddress inetAddress : network.resolveInetAddresses(socketHost)) {
267
inetSocketAddresses.add(new InetSocketAddress(inetAddress, socketPort));
268
}
269
nextInetSocketAddressIndex = 0;
270
}
Obtain a "host" from an
java.net.InetSocketAddress
. This returns a string containing either an actual host name or a numeric IP address.275
276
// Visible for testing
277
static String getHostString(InetSocketAddress socketAddress) {
278
InetAddress address = socketAddress.getAddress();
279
if (address == null) {
280
// The InetSocketAddress was specified with a string (either a numeric IP or a host name). If
281
// it is a name, all IPs for that name should be tried. If it is an IP address, only that IP
282
// address should be tried.
283
return socketAddress.getHostName();
284
}
285
// The InetSocketAddress has a specific address: we should only try that address. Therefore we
286
// return the address and ignore any host name that may be available.
287
return address.getHostAddress();
288
}
这样就能很好的解决这个问题,不存在什么反向解析 然后正向解析的问题了。但是我们Android5.0一下的操作系统怎么办呢????
哈哈 Android 源代码管理的官网上已经将okhttp这个bug 同步过去,bug 号码是#1186
https://github.com/square/okhttp/pull/1186
其实我们创建代理的时候使用不解析的方式创建就可以避免上面的问题!!
https://android.googlesource.com/platform/external/okhttp/+log/android-5.1.0_r1/
https://android.googlesource.com/platform/external/okhttp/+log/android-5.1.0_r1/okhttp/src/main/java/com/squareup/okhttp/internal/http/RouteSelector.java
android / platform / external / okhttp / android-5.1.0_r1 / okhttp / src / main / java / com / squareup / okhttp /internal / http / RouteSelector.java
Android 5.1.0 release 1-----BEGIN PGP SIGNATURE-----Version: GnuPG v1iEYEABECAAYFAlT0jzQACgkQ6K0/gZqxDnhW0ACeIsx37SoxX66T/Vx/uThDRCLQzCQAoJE9d0p9nbad8JBPOEC8OJ/32quz=aQm/-----END PGP SIGNATURE-----
- 2ed0095 Avoid a reverse DNS-lookup for a numeric proxy address by Neil Fuller · 1 year ago
- cc168fe Be consistent about host names in RouteSelector. by Narayan Kamath · 1 year, 2 months ago
- 7c7f22d Allow callers to pass in a custom host resolver implementation. by Lorenzo Colitti · 1 year, 5 months ago
- 3c938a3 Update okhttp to a more recent commit. by Neil Fuller · 1 year, 10 months ago
- 166772b Update okhttp. by Narayan Kamath · 2 years, 1 month ago
https://github.com/square/okhttp/pull/1186
0 0
- Android 4.4.4 -Andoird 5.0.0代理(ProxySlector 中select函数)导致的BUG分析
- fastclick导致的iphone中select点击闪退的bug
- Android中CSS设置select高度的bug解决方法及jq操作select
- linux中select()函数分析
- linux中select()函数分析
- linux中select()函数分析
- linux中select()函数分析
- linux中select()函数分析
- linux中select()函数分析
- linux中select()函数分析
- linux中select()函数分析
- linux中select()函数分析
- linux中select()函数分析
- linux中select()函数分析
- linux中select()函数分析
- linux中select()函数分析
- linux中select()函数分析
- linux中select()函数分析
- 月光博客:写给新手程序员的一封信
- json小例子
- PPI (像素数目)的解释
- 微信支付 Unable to instantiate receiver net.sourceforge.simcpux.AppRegister
- npoi操作excel导出和合并(一)
- Android 4.4.4 -Andoird 5.0.0代理(ProxySlector 中select函数)导致的BUG分析
- 关于生成验证码
- 读写ini配置文件
- JSON的一些使用
- 欢迎使用CSDN-markdown编辑器
- KEIL编译STM32程序出现test.sct(7): error: L6236E: No section matches&nbs
- 排列组合知识
- 代码Overlay机制
- iOS面试、笔试题目总结