我在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 回答
这需要关闭
BIND_V6ONLY
套接字选项 . 有关如何操作的详细信息,请参阅IO::Socket::IP
来源 .另外,回应你的评论
如果记忆能够发挥作用,那并非严格要求 . 你在使用
IO::Socket::IP
时遇到了麻烦,但普通的Socket
东西应该都能正常工作 . 您不需要使用Socket6
因为Socket
2.006已经拥有了所有功能 . 您可以使用以下代码替换代码: