IPv6アドレスでリッスンすることになっているperlの次のプログラムがあり、理論的には、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
IPv4 ワイルドカード アドレス (0.0.0.0) ではなく、IPv6 ワイルドカード アドレス (::) のみをリッスンしているようです。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 $! ");
ソケット オプションのデフォルト値は 1 (このプラットフォームの場合) であり、手動でオーバーライドする必要があると予想されますが、残念ながら! 次のエラーが発生しました:
ベンダーは、c:\socket6\Socket6Server.pl 行 66 で使用されるソケット マクロ IPV6_V6ONLY を定義していません
ここで、「ベンダー」とは何を意味するのだろうか、それは Socket6 モジュール / perl ベンダーまたは OS ベンダーですか?
更新2
答えはhttp://metacpan.org/pod/IO::Socket::IP (V6Only 引数の場合) にあると思います。
プラットフォームがこのオプションの無効化をサポートしていないが、それでも AF_INET 接続と AF_INET6 接続の両方をリッスンしたい場合は、各プロトコルに 1 つずつバインドされた 2 つのリッスン ソケットを作成する必要があります。
そして、これは私のために働いた!しかし、プラットフォームがV6Onlyの無効化をサポートしているかどうかを確認する必要があります(私のプログラムのプロトコル認識コード:()、Javaと比較すると、Javaは自動的にそれを行います(2つのソケットを確認して作成します)。