Как сокет Perl разрешает имена хостов в Linux? - PullRequest
3 голосов
/ 02 октября 2008

У меня есть (из того, что я могу сказать) прекрасно работающая установка Linux (Ubuntu 8.04), где все инструменты (nslookup, curl, wget, firefox и т. Д.) Могут разрешать адреса. Тем не менее, следующий код не работает:

$s = new IO::Socket::INET(
    PeerAddr => 'stackoverflow.com',
    PeerPort => 80,
    Proto => 'tcp',
);

die "Error: $!\n" unless $s;

Я проверил следующие вещи:

  • Perl может разрешать адреса с помощью gethostbyname (т.е. работает приведенный ниже код):

    my $ret = gethostbyname('stackoverflow.com'); print inet_ntoa($ret);

  • Исходный исходный код работает под Windows

  • Вот как это должно работать (т. Е. Должно разрешать имена хостов), поскольку LWP пытается использовать это поведение (на самом деле я натолкнулся на проблему, пытаясь отладить, почему LWP не работал для меня)
  • Запуск сценария не отправляет DNS-запросы (поэтому он даже не пытается разрешить имя). Проверено с Wireshark

Ответы [ 3 ]

7 голосов
/ 02 октября 2008

Вкратце, следующий код из IO :: Socket :: INET

sub _get_addr {
    my($sock,$addr_str, $multi) = @_;
    my @addr;
    if ($multi && $addr_str !~ /^\d+(?:\.\d+){3}$/) {
        (undef, undef, undef, undef, @addr) = gethostbyname($addr_str);
    } else {
        my $h = inet_aton($addr_str);
        push(@addr, $h) if defined $h;
    }
    @addr;
}

предлагает (если вы посмотрите на вызывающего этот код) обходной путь добавления MultiHomed => 1, к вашему коду.

Без этого обходного пути приведенный выше код, по-видимому, пытается вызвать inet_aton("hostname.com") с помощью inet_aton () из Socket.pm. Это работает для меня как в Win32, так и в Unix, так что, я думаю, в этом и кроется перелом.

См. Socket.xs для получения исходного кода inet_aton:

void
inet_aton(host)
    char *  host
    CODE:
    {
        struct in_addr ip_address;
        struct hostent * phe;

        if (phe = gethostbyname(host)) {
            Copy( phe->h_addr, &ip_address, phe->h_length, char );
        } else {
            ip_address.s_addr = inet_addr(host);
        }

        ST(0) = sv_newmortal();
        if(ip_address.s_addr != INADDR_NONE) {
            sv_setpvn( ST(0), (char *)&ip_address, sizeof ip_address );
        }
    }

Похоже, что Perl gethostbyname () работает лучше, чем C gethostbyname () для вас.

0 голосов
/ 06 октября 2008

Не могли бы вы сказать нам точно как ваш код не работает? У вас есть код проверки ошибки, но вы не сообщили, что это за ошибка!

Я только что попробовал оригинальный код (с добавлением «use IO :: Socket :: INET» на моем компьютере с Mac OS X, и он отлично работает.

Я подозреваю, что опция Multihomed - это ненужный хак, а другая проблема - коренная причина вашей проблемы.

0 голосов
/ 02 октября 2008

Убедитесь, что у вас есть заявление

use IO::Socket::INET;

В начале вашего исходного кода. Если вы пропустите это, вы, вероятно, получите сообщение об ошибке:

Не удается найти метод объекта "новый" через пакет "IO :: Socket :: INET"

Кроме того, вы можете убедиться, что DNS работает с использованием Net :: DNS :: Resoler, см. Дополнительную информацию здесь .

use Net::DNS;

my $res = Net::DNS::Resolver->new;

# Perform a lookup, using the searchlist if appropriate.
my $answer = $res->search('example.com');
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...