Internet Protocol version 4 (IPv4)は、長い間インターネット経由でデータを提供するための業界標準のインターネット・プロトコル(IP)バージョンであり続けてきました。Internet Protocol version 6 (IPv6)は次世代のインターネット層プロトコルです。今日では、どちらのバージョンのIPも使用されています。Javaアプリケーションでは、IPv4およびIPv6の両方を自動的にサポートしています。
IPv4とIPv6のもっとも大きな違いはそのアドレス・サイズです。IPv4では32ビットしかありませんが、IPv6では128ビットもあります。詳細は、JavaチュートリアルのIPv4とIPv6の非互換性に関するセクションを参照してください。
このドキュメントでは、次のトピックについて説明します。
JavaでのIPv6は透過的かつ自動的に使用されます。移植は必要ありません。もちろん、ソース・ファイルを再コンパイルする必要もありません。
Javaチュートリアルのソケットからの読取りとソケットへの書込みに関するトピックに記載されているエコー・クライアントの例について考えてみます。この例では、エコー・サーバーに接続し、そのクライアントからデータを受け取って、それをエコー・バックします。エコー・クライアントとエコー・サーバーがIPv6対応のコンピュータで動作している場合は、この例をIPv6モードで実行できます。
IPv6対応プラットフォームでは、クライアントでもサーバーでも、任意のJavaアプリケーションを実行でき、そのアプリケーションは自動的にIPv6対応になります。
Javaネットワーク・スタックはまず、ベースとなるOSでIPv6がサポートされているかどうかを確認します。IPv6がサポートされている場合は、IPv6スタックの使用を試みます。具体的には、デュアルスタック・システムの場合、IPv6ソケットを作成します。個別スタック・システムの場合は、もっと複雑です。Javaランタイムでは、IPv4通信用とIPv6通信用に1つずつ、合計2つのソケットを作成します。クライアント側のTCPアプリケーションでは、ソケットが接続されると、インターネット・プロトコル・ファミリ・タイプが固定されるため、もう1つのソケットを閉じることができます。サーバー側のTCPアプリケーションでは、次のクライアント要求がどのIPファミリ・タイプから送信されるかを知る方法がないため、2つのソケットを維持しておく必要があります。UDPアプリケーションでは、通信の継続期間中、両方のソケットが必要です。
Javaランタイムでは、ネーム・サービスからIPアドレスを取得します。
IPv6をJavaで使用するには、次の内容を知っておく必要はありません。次の各セクションでは、様々な状況の下で何が行われているのかについて説明します。
これはエニーローカル(anylocal)またはワイルドカード・アドレスとも呼ばれます。ソケットがデュアル・スタックのマシン上のIPv6エニーローカル・アドレスにバインドされている場合、そのソケットは、IPv6トラフィックとIPv4トラフィックの両方を受け入れることができます。ソケットがIPv4 (IPv4マップ)エニーローカル・アドレスにバインドされている場合、そのソケットはIPv4トラフィックのみを受け入れることができます。Javaランタイムでは、関連するシステム・プロパティがIPv4スタックを使用するように設定されていないかぎり、常にデュアル・スタックのマシン上でIPv6エニーローカル・アドレスへのバインドを試みます。
::
にバインドされると、ServerSocket.acceptメソッドは、IPv6ホストとIPv4ホストの両方からの接続を受け入れます。現在のJavaプラットフォームAPIでは、IPv6ホストからの接続だけを受け入れるように指定する方法はありません。
アプリケーションでは、NetworkInterfaceを使用してインタフェースを列挙し、各IPv6アドレスにServerSocketChannelをバインドして、New I/O APIからのセレクタを使用してそれらのソケットからの接続を受け入れることができます。
ただし、前述の動作を変更する、新しいソケット・オプションがあります。「Basic Socket Interface Extensions for IPv6」では、新しいIPレベルのソケット・オプションとして、IPV6_V6ONLYが導入されています。このソケット・オプションは、AF_INET6ソケットをIPv6通信だけに限定します。通常、AF_INET6ソケットは、IPv4およびIPv6の両方の通信のために使用できます。アプリケーションによっては、AF_INET6ソケットの使用をIPv6通信だけに限定したい場合があります。そのようなアプリケーションでは、IPV6_V6ONLYソケット・オプションを定義します。このオプションをオンに設定すると、IPv6パケットだけを送受信するためにそのソケットを使用できます。デフォルトでは、このオプションはオフになっています。現在のところ、Java SEではこのソケット・オプションをサポートしていないので注意してください。今後のリリースで追加される可能性があります
ループバック・アドレスを指定されたパケットは、決してリンク上に送信したり、IPv6ルーターによって転送したりしないでください。IPv4とIPv6には2つの異なるループバック・アドレスがあり、それぞれ別個に処理されます。
IPv4とIPv6のアドレスは、「::」のときを除いて、別々のアドレス空間を占めます。
このアドレス・タイプは、ホストおよびルーターがIPv6パケットをIPv4ルーティング・インフラストラクチャ上で動的にトンネルするために使用されることを目的として作成されましたが、Internet Engineering Task Force (IETF)によって非推奨になりました。
これは、IPv4アドレスを表現するために使用されるIPv6アドレスです。このアドレスを利用すると、ネイティブ・プログラムでは、IPv4ノードとIPv6ノードの両方と通信する際に、同じアドレス・データ構造と、さらには同じソケットを使用できます。このため、IPv4マップ・アドレスをサポートするデュアルスタック・ノード上では、IPv6アプリケーションはIPv4ピアとIPv6ピアの両方と通信できます。IPv4のデータグラムを送受信するのに必要なベースとなる諸処理はOSが実行して、その結果をIPv6の宛先ソケットに渡します。また、OSは、必要なときにIPv4マップIPv6アドレスを合成します。
Javaでは、このアドレスは内部の表現に使用され、機能上の役割はありません。JavaからIPv4マップ・アドレスが返されることはありません。IPv4マップ・アドレスの構文が、バイト配列とテキスト表現の両方で理解されます。ただし、そのアドレスはIPv4アドレスに変換されます。
デュアル・スタック・マシンでは、優先されるプロトコル・スタック(IPv4またはIPv6)と、優先されるアドレス・ファミリの型(inet4またはinet6)を設定するためのシステム・プロパティが提供されます。
デフォルトでは、IPv6スタックが優先されます。デュアル・スタック・マシンでは、IPv6ソケットがIPv4ピアとIPv6ピアの両方と通信できるためです。
この設定を変更するには、java.net.preferIPv4Stack=<true|false>
システム・プロパティを使用します。
デフォルトでは、IPv4アドレスがIPv6アドレスよりも優先されます。たとえば、ネーム・サービス(DNSサービスなど)への問合せ時は、IPv4アドレスがIPv6アドレスよりも先に返されます。この選択には、次の2つの理由があります。
%d.%d.%d.%d
など)を想定しているものがあります。IPv4アドレスを使用すれば、予期しない動作を最小限にできます。この設定を変更するには、java.net.preferIPv6Addresses=<true|false>
システム・プロパティを使用します
このさき何年もの間(永久にではないとしても)、インターネットはIPv6ノードとIPv4ノードが混在した状態になるでしょう。このため、IPv4ノードの大規模なインストール・ベースとの互換性が、IPv4からIPv6への移行を成功させるために重要です。デュアル・スタック(RFC 1933で定義されている)は、円滑な移行を保証するための主要なメカニズムの1つです。もう1つのメカニズムはIPv6パケットのトンネリングですが、このメカニズムとJDKとの関連性はIPv4互換アドレスに関係するものだけです。前者のメカニズムは、JDKともっとも関連性があります。デュアル・スタックには、IPv4とIPv6の両方のバージョンのインターネット・プロトコルを実装することが含まれます。
デュアルスタック・ノードの一般的な特性は、IPv6ソケットがIPv4ピアおよびIPv6ピアの両方とトランスポート層(TCPまたはUDP)で通信できるということです。ネイティブ・レベルでは、IPv6ソケットは、IPv4マップIPv6アドレスを使ってIPv4と通信します。ただし、ソケットがピアのアドレス型を調べないかぎり、IPv4ピアまたはIPv6ピアのどちらと通信しているかをソケットが認識することはありません。アドレス型に関係した内部の処理と変換はすべて、デュアルプロトコル・スタックによって実行されます。
注: IPv4マップ・アドレスは、デュアルプロトコル・スタックの実装でのみ意味を持ちます。これは、IPv6アドレスを模倣して(IPv6アドレスと同じ形式にするなどして)、アドレスがIPv6ソケットに渡されるようにするために使用します。概念上のレベルでは特に役割がなく、その役割はJava APIのレベルに限定されています。IPv4マップ・アドレスの解析はサポートされていますが、IPv4マップ・アドレスが返されることはありません。
(ノード) | V4のみ | V4/V6 | V6のみ |
---|---|---|---|
V4のみ | x | x | 通信不可 |
V4/V6 | x | x | x |
V6のみ | 通信不可 | x | x |
一番上の行と左端の列は、通信を試みるノードの種類を表しています。「x」は、それらのノードが互いに通信できることを示します。
次の通信シナリオでは、host1またはhost2のどちらかをネイティブ・アプリケーションにできます。
java.net.preferIPv4Stack (default: false)
オペレーティング・システムでIPv6が利用できる場合、ベースとなるネイティブ・ソケットはIPv6ソケットになります。これにより、Javaアプリケーションは、IPv4ホストとIPv6ホストの両方に接続したり、両方のホストからの接続を受け入れたりできます。
IPv4ソケットだけを使用するよう設定されているアプリケーションでは、このプロパティをtrueに設定できます。つまり、そのアプリケーションはIPv6ホストと通信できないということです。
java.net.preferIPv6Addresses (default: false)
オペレーティング・システムでIPv6が利用できる場合、デフォルトの設定では、IPv4マップ・アドレスがIPv6アドレスよりも優先されます。これは、下位互換性の理由によります。たとえば、IPv4専用のサービスへのアクセスに依存するアプリケーションや、%d.%d.%d.%d
表現のIPアドレスに依存するアプリケーションとの互換性のためです。
このプロパティをtrueに設定すると、IPv6アドレスをIPv4アドレスに優先して使用するように設定を変更できます。これにより、アプリケーションがIPv6サービスに接続されると予想される環境で、アプリケーションのテストおよび配備を行うことができます。
sun.net.spi.nameservice.provider.<n>=<default|dns,sun|...>
使用できるネーム・サービス・プロバイダを指定します。デフォルトでは、Javaランタイムは、ファイルやNetwork Information Service (NIS)など、システムで構成された名前検索メカニズムを使用します。このオプションを設定すると、独自のものを指定できます。<n>
には正の数値を指定します。この数値は優先順位を示しており、小さい値ほど優先順位が高くなります。JNDIを介して1つのDNSネーム・サービス・プロバイダが提供されており、その名前はdns,sun
です。
sun.net.spi.nameservice.nameservers=<server1_ipaddr,server2_ipaddr ...>
使用するDNSサーバーを指すIPアドレスを、カンマで区切ったリストとして指定できます。
sun.net.spi.nameservice.domain=<domainname>
このプロパティでは、デフォルトのDNSドメイン名(たとえば、eng.example.com
)を指定します。