这里有一个相关的问题,但是我不知道如何将答案应用到mechanize/urllib2:how to force python httplib library to use only A requests
基本上,给定这个简单的代码:
#!/usr/bin/python
import urllib2
print urllib2.urlopen('http://python.org/').read(100)
这导致wireshark说:
0.000000 10.102.0.79 -> 8.8.8.8 DNS Standard query A python.org
0.000023 10.102.0.79 -> 8.8.8.8 DNS Standard query AAAA python.org
0.005369 8.8.8.8 -> 10.102.0.79 DNS Standard query response A 82.94.164.162
5.004494 10.102.0.79 -> 8.8.8.8 DNS Standard query A python.org
5.010540 8.8.8.8 -> 10.102.0.79 DNS Standard query response A 82.94.164.162
5.010599 10.102.0.79 -> 8.8.8.8 DNS Standard query AAAA python.org
5.015832 8.8.8.8 -> 10.102.0.79 DNS Standard query response AAAA 2001:888:2000:d::a2
这是一个5秒的延迟!
我的系统中没有启用IPv6(gentoo是用USE=-ipv6
编译的),所以我认为python甚至没有任何理由尝试IPv6查找。
上面提到的问题建议显式地将套接字类型设置为AF_INET
,这听起来不错。我不知道如何强制urllib或mechanize使用我创建的任何套接字。
编辑:我知道AAAA查询是问题所在,因为其他应用程序也有延迟,当我在禁用ipv6的情况下重新编译时,问题就消失了。。。除了在python中仍然执行AAAA请求。
同样的问题,根据J.J.提供的信息,这里有一个丑陋的黑客攻击(风险自负)。
这基本上是将
socket.getaddrinfo(..)
的family
参数强制为socket.AF_INET
,而不是使用socket.AF_UNSPEC
(零,这似乎是在socket.create_connection
中使用的),这不仅适用于来自urllib2
的调用,而且也适用于对socket.getaddrinfo(..)
的所有调用:至少在这个简单的例子中,这对我有效。
没有答案,只有几个数据点。DNS解析似乎来自
HTTPConnection.connect()
中的httplib.py
(python 2.5.4 stdlib上的第670行)代码流大致如下:
对发生的事情有几点看法:
socket.getaddrinfo()
的第三个参数限制套接字系列,即IPv4与IPv6。通过零返回所有族。零被硬编码到stdlib中。将主机名传递到
getaddrinfo()
将导致名称解析——在启用了IPv6的OS X框中,a和AAAA记录都会输出,两个答案都会返回,并且都会返回。connect循环的其余部分尝试每个返回的地址,直到一个成功为止
例如:
一些猜测:
由于
getaddrinfo()
中的套接字系列硬编码为零,您将无法通过urllib中支持的一些API接口重写A与AAAA记录。除非mechanize出于其他原因执行自己的名称解析,否则mechanize也不能。从连接循环的构造来看,这是通过设计实现的。python的socket模块是POSIX socket api的一个瘦包装器;我期望它们正在解析系统上配置的每个可用系列。仔细检查Gentoo的IPv6配置。
当被问及python.org的AAAA时,DNS服务器8.8.8.8(googledns)会立即回复。因此,我们在您发布的跟踪中没有看到此回复,这可能表明此数据包没有返回(这在UDP中发生)。如果这种损失是随机的,那是正常的。如果是系统性的,则意味着网络设置中存在问题,可能是防火墙断开,导致第一个AAAA回复无法返回。
5秒的延迟来自存根解析程序。在这种情况下,如果是随机的,可能是运气不好,但与IPv6无关,对A记录的回复也可能失败。
禁用IPv6似乎是一个非常奇怪的举动,就在最后一个IPv4地址被分发的两年前!
相关问题 更多 >
编程相关推荐