2013-08-24 17 views
7

Nếu tôi sử dụng wget để lấy một cái gì đó từ máy chủ geonames.org, nó báo cáo hai địa chỉ IP, và là người đầu tiên thất bại nhưng nó được nó từ thứ hai:Làm thế nào để thất bại trên

Resolving ws.geonames.org (ws.geonames.org)... 5.9.41.208, 176.9.107.169 
Connecting to ws.geonames.org (ws.geonames.org)|5.9.41.208|:80... failed: Connection refused. 
Connecting to ws.geonames.org (ws.geonames.org)|176.9.107.169|:80... connected. 
HTTP request sent, awaiting response... 200 OK 

Nhưng tiếc là tôi phải truy cập thông qua perl bằng cách sử dụng LWP :: UserAgent và HTTP :: Request. Làm thế nào tôi có thể làm cho họ thử IP thứ hai nếu lần đầu tiên không thành công?

my $ua = LWP::UserAgent->new; 
my $req = HTTP::Request->new(
    GET => 
     "http://ws.geonames.org/countrySubdivision?lat=$lat&lng=$long&radius=$radius&username=xyzzy"); 

my $res = $ua->request($req); 
+0

Bạn có chắc chắn rằng đây không phải là hành vi mặc định cho LWP :: UserAgent? Sau khi đào qua mã LWP :: UserAgent ngày hôm nay, nó sẽ xuất hiện khi socket đang được kết nối sâu bên trong IO :: Socket :: INET :: configure() nó sẽ thử tất cả các địa chỉ IP được trả về cho một hostname và sẽ giải quyết cho IP đầu tiên mà nó có thể kết nối tới. –

+0

@RobWells, vấn đề là có sự khác biệt giữa "có thể mở một ổ cắm" và "nhận được phản hồi HTTP hợp lệ trong thời gian chờ". 'wget' sẽ chuyển sang phần tiếp theo nếu phần thứ hai thất bại, nhưng' LWP :: UserAgent' thì không. –

+1

cổ vũ @Paul. Tôi đã thấy rằng bạn phải kích hoạt một cách rõ ràng tùy chọn MultiHome để có được hành vi đó lặp trên nhiều IP. Nó bị chôn vùi trong tình trạng hỗn loạn của Perl OO -> SUPER :: foo nên thật vui khi theo dõi! (-: –

Trả lời

6

Bạn có thể làm điều đó cho mình: có được tất cả các địa chỉ IP với sự giúp đỡ của Net::DNS::Resolver, và sau đó thử tất cả các địa chỉ IP cho đến khi bạn nhận được một phản ứng thành công. Lưu ý rằng bạn phải tự cung cấp tiêu đề "Máy chủ" nếu làm việc với địa chỉ IP, trong trường hợp máy chủ đang thực hiện các máy chủ ảo dựa trên tên.

Giống như các dòng sau có thể hoạt động. Có thể thậm chí có một mô-đun CPAN cho điều này, tôi không kiểm tra:

use Net::DNS; 
use LWP::UserAgent; 

my @addrs; 
{ 
    my $res = Net::DNS::Resolver->new; 
    my $query = $res->search("ws.geonames.org"); 
    if ($query) { 
     for my $rr ($query->answer) { 
      if ($rr->type eq "A") { 
       push @addrs, $rr->address; 
      } 
     } 
    } else { 
     die "DNS query failed: ", $res->errorstring, "\n"; 
    } 
} 

my $ua = LWP::UserAgent->new; 

my $res; 
for my $addr (@addrs) { 
    $res = $ua->get("http://$addr/countrySubdivision?lat=$lat&lng=$long&radius=$radius&username=xyzzy", Host => 'ws.geonames.org'); 
    last if $res->is_success; 
} 
+0

xin lỗi, đã không thực sự thấy rằng trước khi viết bình luận.Tôi do đó đã xóa các bình luận vì nó không áp dụng ở tất cả các –

+0

OK, tôi cũng đã xóa trả lời của tôi :-) –

1

Giải pháp từ Slaven là OK trừ khi địa chỉ IP không thể truy cập trực tiếp. Trong trường hợp đó, những điều sau đây phù hợp với tôi:

local @LWP::Protocol::http::EXTRA_SOCK_OPTS = (
              PeerAddr => 'my_hostname', 
              MultiHomed => 1, 
             ); 
my $response = $ua->post('https://my_hostname/...', ...);