首页 文章

perl Socket6仅绑定到一个通配符地址

提问于
浏览
0

我在perl中有以下程序,它应该监听IPv6地址,理论上应该同时服务于IPv4(通过IPv4映射的IPv6地址)和双栈上的IPv6客户端 .

use Socket;
use Socket6;

@res = getaddrinfo('', 8086, AF_UNSPEC, SOCK_STREAM,0, AI_PASSIVE);
my @ipv6Result;

while(scalar(@res)>=5){
    my @currentResult = @res;
    ($family, $socktype, $proto, $saddr, $canonname, @res) = @res;
    if($family == AF_INET6){
        @ipv6Result = @currentResult;
    }
} 

if(@ipv6Result){
    ($family, $socktype, $proto, $saddr, $canonname) = @ipv6Result;
}

socket(Socket_Handle, $family, $socktype,$proto) || next;
bind(Socket_Handle,$saddr  )    || die "bind: $!";
listen(Socket_Handle, 1)                       || die "listen: $!";
$paddr = accept(Client,Socket_Handle) || die "accept: $!";

运行此之后,netstat给出了以下观察:

c:\Perl\bin>netstat -nao | findstr 8086
TCP    [::]:8086              [::]:0                 LISTENING       2892

看起来,它只监听IPv6通配符地址(::)而不是IPv4通配符地址(0.0.0.0) . 我无法从IPv4客户端连接此服务器进程,但能够通过IPv6客户端连接 .

我在java中尝试了类似的服务器程序,如下所示(在相同的设置上):

import java.net.ServerSocket;
public class CodeTCPServer {
    public static void main(String[] args) throws Exception{
        new ServerSocket(8086).accept();
    }
}

netstat输出如下:

C:\Users\Administrator>netstat -nao | findstr 8086
TCP    0.0.0.0:8086           0.0.0.0:0              LISTENING       3820
TCP    [::]:8086              [::]:0                 LISTENING       3820

似乎是在侦听IPv6和IPv4,我也可以从IPv4和IPv6客户端连接它 .

如果我在Linux机器上运行相同的perl程序它工作正常,我能够通过IPv4和IPv6客户端连接到它 .

我想知道,如果Windows上的某些内容阻止了perl程序监听IPv4和IPv6(但是出于同样的原因它应该也停止了java程序) . 如果程序逻辑存在一些问题,那么它也不应该在linux上运行 .

(我现在正在使用Socket6,因为我不能在Windows上以某种方式使用perl对IPv6的内置支持,我正在与作者沟通以使其在我的设置上工作)

更新:

我刚试过以下内容:

setsockopt (Socket_Handle, IPPROTO_IPV6, IPV6_V6ONLY, 0 ) or print("\nFailed to set IPV6_V6ONLY $! ");

预计socket选项的默认值为1(对于这个平台),我必须手动覆盖它,但是唉!我收到以下错误:

您的供应商尚未定义Socket宏IPV6_V6ONLY,在c:\ socket6 \ Socket6Server.pl第66行中使用

现在我想知道'供应商'是什么意思,是Socket6模块/ perl供应商还是OS供应商?

UPDATE2

我认为答案在http://metacpan.org/pod/IO::Socket::IP中给出(对于V6Only参数)

如下所示:如果您的平台不支持禁用此选项但您仍想监听AF_INET和AF_INET6连接,则必须创建两个侦听套接字,一个绑定到每个协议 .

这对我有用!但后来我需要检查平台是否支持V6Only禁用(程序中的协议感知代码:()),与Java相比,Java自动为我做(检查并创建2个套接字) .

1 回答

  • 1

    这需要关闭 BIND_V6ONLY 套接字选项 . 有关如何操作的详细信息,请参阅 IO::Socket::IP 来源 .


    另外,回应你的评论

    我现在正在使用Socket6,因为我不能在Windows上以某种方式使用perl对IPv6的内置支持,我正在与作者沟通以使其在我的设置上工作)

    如果记忆能够发挥作用,那并非严格要求 . 你在使用 IO::Socket::IP 时遇到了麻烦,但普通的 Socket 东西应该都能正常工作 . 您不需要使用 Socket6 因为 Socket 2.006已经拥有了所有功能 . 您可以使用以下代码替换代码:

    use Socket qw( :addrinfo SOCK_STREAM AF_INET6 );
    
    my ($err, @res) = getaddrinfo('', 8086,
       { socktype => SOCK_STREAM, flags => AI_PASSIVE });
    my $ipv6Result;
    
    my $current;
    while(@res){
        $current = shift @res;
        if($current->{family} == AF_INET6) {
            $ipv6Result = $current;
        }
    }
    
    if($ipv6Result) {
        $current = $ipv6Result;
    }
    
    socket(my $sock, $current->{family}, $current->{socktype}, $current->{proto}) or next;
    bind(my $sock ,$current->{addr}) or die "bind: $!";
    listen(my $sock, 1) or die "listen: $!";
    
    my $paddr = accept(my $client, $sock) or die "accept: $!";
    

相关问题