Perl 套接字如何在 Linux 下解析主机名?

发布于 2024-07-06 16:59:25 字数 632 浏览 5 评论 0原文

我有一个(据我所知)完美运行的 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 验证

I have a (from what I can tell) perfectly working Linux setup (Ubuntu 8.04) where all tools (nslookup, curl, wget, firefox, etc) are able to resolve addresses. Yet, the following code fails:

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

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

I verified the following things:

  • Perl is able to resolve addresses with gethostbyname (ie the code below works):

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

  • The original source code works under Windows

  • This is how it supposed to work (ie. it should resolve hostnames), since LWP tries to use this behavior (in fact I stumbled uppon the problem by trying to debug why LWP wasn't working for me)
  • Running the script doesn't emit DNS requests (so it doesn't even try to resolve the name). Verified with Wireshark

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

柠北森屋 2024-07-13 16:59:25

快速浏览一下,来自 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、到你的代码。

如果没有这种解决方法,上面的代码似乎会尝试使用 Socket.pm 中的 inet_aton() 来调用 inet_aton("hostname.com")。 这对我来说在 Win32 和 Unix 上都有效,所以我想这就是你的问题所在。

inet_aton的源代码参见Socket.xs

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() 更适合您。

From a quick look, the following code from 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;
}

suggests (if you look at the caller of this code) the work-around of adding MultiHomed => 1, to your code.

Without that work-around, the above code appears to try to call inet_aton("hostname.com") using the inet_aton() from Socket.pm. That works for me in both Win32 and Unix, so I guess that is where the breakage lies for you.

See Socket.xs for the source code of 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 );
        }
    }

It appears that the Perl gethostbyname() works better than the C gethostbyname() for you.

疾风者 2024-07-13 16:59:25

您能否准确地告诉我们您的代码如何失败了? 你那里有错误检查代码,但你还没有报告错误是什么!

我刚刚尝试了原始代码(在我的 Mac OS X 机器上添加了“use IO::Socket::INET”并且工作正常。

我怀疑 Multihomed 选项是不必要的 hack,其他一些问题是你的问题的根本原因。

Could you perhaps tells us exactly how your code fails? You've got error checking code in there but you haven't reported what the error is!

I've just tried the original code (with the addition of the "use IO::Socket::INET" on my Mac OS X machine and it works fine.

I suspect that the Multihomed option is an unnecessary hack and some other issue is the root cause of your problem.

彼岸花似海 2024-07-13 16:59:25

确保

use IO::Socket::INET;

您的源代码开头有这样的语句。 如果您忽略这一点,您可能会收到错误消息:

无法通过以下方式找到对象方法“new”
包“IO::Socket::INET”

除此之外,您还可以使用 Net::DNS::Resoler 验证 DNS 是否正常工作,请参阅更多信息 此处

use Net::DNS;

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

# Perform a lookup, using the searchlist if appropriate.
my $answer = $res->search('example.com');

Make sure that you have the statement

use IO::Socket::INET;

At the beginning of your source code. If you leave this out, you are probably getting the error message:

Can't locate object method "new" via
package "IO::Socket::INET"

Beyond that you might verify that DNS is working using Net::DNS::Resoler, see more information here.

use Net::DNS;

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

# Perform a lookup, using the searchlist if appropriate.
my $answer = $res->search('example.com');
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文