簡體   English   中英

強制python mechanize / urllib2只使用A請求?

[英]Force python mechanize/urllib2 to only use A requests?

這是一個相關的問題,但我無法弄清楚如何應用mechanize / urllib2的答案: 如何強制python httplib庫只使用A請求

基本上,給出這個簡單的代碼:

#!/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(用USE=-ipv6編譯的gentoo)所以我不認為python有任何理由甚至嘗試IPv6查找。

上面提到的問題建議明確地將套接字類型設置為AF_INET ,這聽起來很棒。 我不知道如何強制urllib或機械化使用我創建的任何套接字。

編輯 :我知道AAAA查詢是問題,因為其他應用程序也有延遲,一旦我禁用ipv6重新編譯,問題就消失了......除了仍在執行AAAA請求的python中。

遇到同樣的問題,根據JJ提供的信息,這是一個丑陋的黑客(使用風險自負......)。

這基本上強制socket.getaddrinfo(..)family參數為socket.AF_INET而不是使用socket.AF_UNSPEC (零,這似乎是在socket.create_connection使用的),不僅適用於來自urllib2調用,而且應該這樣做對於所有對socket.getaddrinfo(..)調用:

#--------------------
# do this once at program startup
#--------------------
import socket
origGetAddrInfo = socket.getaddrinfo

def getAddrInfoWrapper(host, port, family=0, socktype=0, proto=0, flags=0):
    return origGetAddrInfo(host, port, socket.AF_INET, socktype, proto, flags)

# replace the original socket.getaddrinfo by our version
socket.getaddrinfo = getAddrInfoWrapper

#--------------------
import urllib2

print urllib2.urlopen("http://python.org/").read(100)

至少在這個簡單的情況下,這對我有用。

沒有答案,但有一些數據點。 DNS解析似乎來自HTTPConnection.connect() httplib.py HTTPConnection.connect()我的python 2.5.4 stdlib上的第670行)

代碼流大致是:

for res in socket.getaddrinfo(self.host, self.port, 0, socket.SOCK_STREAM):
    af, socktype, proto, canonname, sa = res
    self.sock = socket.socket(af, socktype, proto)
    try:
        self.sock.connect(sa)
    except socket.error, msg: 
        continue
    break

關於發生了什么的一些評論:

  • socket.getaddrinfo()的第三個參數限制套接字系列 - 即IPv4與IPv6。 傳遞零返回所有家庭。 零被硬編碼到stdlib中。

  • 將主機名傳遞給getaddrinfo()將導致名稱解析 - 在啟用了IPv6的OS X框中,A和AAAA記錄都會消失,兩個答案都會立即返回並返回。

  • 連接循環的其余部分嘗試每個返回的地址,直到一個成功

例如:

>>> socket.getaddrinfo("python.org", 80, 0, socket.SOCK_STREAM)
[
 (30, 1, 6, '', ('2001:888:2000:d::a2', 80, 0, 0)), 
 ( 2, 1, 6, '', ('82.94.164.162', 80))
]
>>> help(socket.getaddrinfo)
getaddrinfo(...)
    getaddrinfo(host, port [, family, socktype, proto, flags])
        -> list of (family, socktype, proto, canonname, sockaddr)

一些猜測:

  • 由於getaddrinfo()的套接字系列硬編碼為零,因此您將無法通過urllib中的某些受支持的API接口覆蓋A與AAAA記錄。 除非機械化由於某些其他原因而自行解析名稱,否則機械化也不能。 從連接循環的構造,這是By Design。

  • python的套接字模塊是一個圍繞POSIX套接字API的瘦包裝器; 希望他們能夠解決系統上所有可用和配置的系列。 仔細檢查Gentoo的IPv6配置。

最可能的原因是出口防火牆損壞 例如,Juniper防火牆可以解決這個問題,盡管它們有可用的解決方法

如果您無法讓網絡管理員修復防火牆,您可以嘗試基於主機的解決方法。 將此行添加到/etc/resolv.conf

options single-request-reopen

手冊頁解釋得很好:

解析器對A和AAAA請求使用相同的套接字。 有些硬件錯誤地只發回一個回復。 當發生這種情況時,客戶端系統將坐下並等待第二個回復。 啟用此選項會更改此行為,以便在未正確處理來自同一端口的兩個請求時,它將關閉套接字並在發送第二個請求之前打開一個新套接字。

當被問及python.org的AAAA時,DNS服務器8.8.8.8(谷歌DNS)立即回復。 因此,我們在您發布的跟蹤中沒有看到此回復的事實可能表明該數據包沒有返回(這發生在UDP中)。 如果這種損失是隨機的,那是正常的。 如果它是系統的,則表示您的網絡設置存在問題,可能是防火牆損壞,導致第一個AAAA回復無法恢復。

5秒延遲來自您的存根解析器。 在這種情況下,如果它是隨機的,那可能是運氣不好,但與IPv6無關,A記錄的回復也可能失敗。

在最后一個IPv4地址分發前兩年,禁用IPv6似乎是一個非常奇怪的舉動!

% dig @8.8.8.8  AAAA python.org

; <<>> DiG 9.5.1-P3 <<>> @8.8.8.8 AAAA python.org
; (1 server found)
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 50323
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;python.org.                    IN      AAAA

;; ANSWER SECTION:
python.org.             69917   IN      AAAA    2001:888:2000:d::a2

;; Query time: 36 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Sat Jan  9 21:51:14 2010
;; MSG SIZE  rcvd: 67

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM