1. 概要

この記事では、ネットワークインターフェイスと、Javaでプログラムでそれらにアクセスする方法に焦点を当てます。

簡単に言えば、ネットワークインターフェイスは、デバイスとそのネットワーク接続の間の相互接続のポイントです。

日常の言葉では、ネットワークインターフェイスカード(NIC)という用語でそれらを参照しますが、すべてがハードウェア形式である必要はありません。

たとえば、Webおよびネットワークアプリケーションのテストでよく使用される一般的なローカルホストIP 127.0.0.1 は、直接ハードウェアインターフェイスではないループバックインターフェイスです。

もちろん、システムには、有線イーサネット、WIFI、Bluetoothなどの複数のアクティブなネットワーク接続があることがよくあります。

Javaでは、それらと直接対話するために使用できる主なAPIは、java.net.NetworkInterfaceクラスです。 それで、すぐに始めるために、完全なパッケージをインポートしましょう:

import java.net.*;

2. なぜネットワークインターフェイスにアクセスするのですか?

ほとんどのJavaプログラムは、おそらくそれらと直接対話することはありません。 ただし、この種の低レベルのアクセスが必要な場合は、特別なシナリオがあります。

これらの中で最も優れているのは、システムに複数のカードがあり、でソケットを使用するための特定のインターフェイスを自由に選択できるようにする場合です。 このようなシナリオでは、通常、名前はわかっていますが、必ずしもIPアドレスである必要はありません。

通常、特定のサーバーアドレスへのソケット接続を行う場合は、次のようにします。

Socket socket = new Socket();
socket.connect(new InetSocketAddress(address, port));

このようにして、システムは適切なローカルアドレスを選択し、それにバインドして、ネットワークインターフェイスを介してサーバーと通信します。 ただし、このアプローチでは、独自のアプローチを選択することはできません。

ここで仮定を立てます。 住所はわかりませんが、名前はわかります。 デモンストレーションの目的で、ループバックインターフェイスを介した接続が必要であると仮定します。慣例により、その名前は lo であり、少なくともLinuxおよびWindowsシステムでは、OSXではlo0です。

NetworkInterface nif = NetworkInterface.getByName("lo");
Enumeration<InetAddress> nifAddresses = nif.getInetAddresses();

Socket socket = new Socket();
socket.bind(new InetSocketAddress(nifAddresses.nextElement(), 0));
socket.connect(new InetSocketAddress(address, port));

したがって、最初に lo に接続されているネットワークインターフェイスを取得し、それに接続されているアドレスを取得し、ソケットを作成し、コンパイル時にさえわからない列挙されたアドレスのいずれかにバインドしてから接続します。

NetworkInterface オブジェクトには、名前とそれに割り当てられたIPアドレスのセットが含まれています。 したがって、これらのアドレスのいずれかにバインドすると、このインターフェイスを介した通信が保証されます。

これは、APIについて特別なことを何も言っていません。 ローカルアドレスをlocalhostにする場合、バインディングコードを追加しただけで、最初のスニペットで十分です。

さらに、ローカルホストには既知のアドレス 127.0.0.1 があり、ソケットを簡単にバインドできるため、いくつかの手順をすべて実行する必要はありません。

ただし、あなたの場合、 lo は、Bluetooth – net1 、ワイヤレスネットワーク– net0 、イーサネット– eth0などの他のインターフェイスを表している可能性があります。 。 このような場合、コンパイル時にIPアドレスがわかりません。

3. ネットワークインターフェイスの取得

このセクションでは、利用可能なインターフェースを取得するために利用可能な他のAPIについて説明します。 前のセクションでは、これらのアプローチの1つだけを見ました。 getByName()静的メソッド。

NetworkInterface クラスにはパブリックコンストラクターがないため、もちろん新しいインスタンスを作成することはできません。 代わりに、利用可能なAPIを使用してAPIを取得します。

これまで見てきたAPIは、指定された名前でネットワークインターフェイスを検索するために使用されます。

@Test
public void givenName_whenReturnsNetworkInterface_thenCorrect() {
    NetworkInterface nif = NetworkInterface.getByName("lo");

    assertNotNull(nif);
}

名前がない場合は、nullを返します。

@Test
public void givenInExistentName_whenReturnsNull_thenCorrect() {
    NetworkInterface nif = NetworkInterface.getByName("inexistent_name");

    assertNull(nif);
}

2番目のAPIはgetByInetAddress()です。これには、既知のパラメーターを指定する必要があります。今回は、IPアドレスを指定できます。

@Test
public void givenIP_whenReturnsNetworkInterface_thenCorrect() {
    byte[] ip = new byte[] { 127, 0, 0, 1 };

    NetworkInterface nif = NetworkInterface.getByInetAddress(
      InetAddress.getByAddress(ip));

    assertNotNull(nif);
}

またはホストの名前:

@Test
public void givenHostName_whenReturnsNetworkInterface_thenCorrect()  {
    NetworkInterface nif = NetworkInterface.getByInetAddress(
      InetAddress.getByName("localhost"));

    assertNotNull(nif);
}

または、ローカルホストに固有の場合:

@Test
public void givenLocalHost_whenReturnsNetworkInterface_thenCorrect() {
    NetworkInterface nif = NetworkInterface.getByInetAddress(
      InetAddress.getLocalHost());

    assertNotNull(nif);
}

もう1つの方法は、ループバックインターフェイスを明示的に使用することです。

@Test
public void givenLoopBack_whenReturnsNetworkInterface_thenCorrect() {
    NetworkInterface nif = NetworkInterface.getByInetAddress(
      InetAddress.getLoopbackAddress());

    assertNotNull(nif);
}

Java 7以降でのみ利用可能になった3番目のアプローチは、そのインデックスによってネットワークインターフェイスを取得することです。

NetworkInterface nif = NetworkInterface.getByIndex(int index);

最後のアプローチでは、 getNetworkInterfacesAPIを使用します。 システムで使用可能なすべてのネットワークインターフェイスの列挙を返します。 返されたオブジェクトをループで取得するのは私たちの責任です。標準のイディオムはListを使用します。

Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();

for (NetworkInterface nif: Collections.list(nets)) {
    //do something with the network interface
}

4. ネットワークインターフェイスパラメータ

オブジェクトを取得した後、1つから取得できる貴重な情報がたくさんあります。 最も便利なものの1つは、それに割り当てられたIPアドレスのリストです

2つのAPIを使用してIPアドレスを取得できます。 最初のAPIはgetInetAddresses()です。 これは、InetAddressインスタンスのEnumerationを返します。これは、適切と見なされるときに処理できます。

@Test
public void givenInterface_whenReturnsInetAddresses_thenCorrect()  {
    NetworkInterface nif = NetworkInterface.getByName("lo");
    Enumeration<InetAddress> addressEnum = nif.getInetAddresses();
    InetAddress address = addressEnum.nextElement();

    assertEquals("127.0.0.1", address.getHostAddress());
}

2番目のAPIはgetInterfaceAddresses()です。 InetAddressインスタンスよりも強力なInterfaceAddressインスタンスのListを返します。 たとえば、IPアドレスとは別に、ブロードキャストアドレスに関心がある場合があります。

@Test
public void givenInterface_whenReturnsInterfaceAddresses_thenCorrect() {
    NetworkInterface nif = NetworkInterface.getByName("lo");
    List<InterfaceAddress> addressEnum = nif.getInterfaceAddresses();
    InterfaceAddress address = addressEnum.get(0);

    InetAddress localAddress=address.getAddress();
    InetAddress broadCastAddress = address.getBroadcast();

    assertEquals("127.0.0.1", localAddress.getHostAddress());
    assertEquals("127.255.255.255",broadCastAddress.getHostAddress());
}

割り当てられた名前とIPアドレスを超えて、インターフェイスに関するネットワークパラメータにアクセスできます。 稼働しているかどうかを確認するには:

@Test
public void givenInterface_whenChecksIfUp_thenCorrect() {
    NetworkInterface nif = NetworkInterface.getByName("lo");

    assertTrue(nif.isUp());
}

ループバックインターフェイスであるかどうかを確認するには、次の手順に従います。

@Test
public void givenInterface_whenChecksIfLoopback_thenCorrect() {
    NetworkInterface nif = NetworkInterface.getByName("lo");

    assertTrue(nif.isLoopback());
}

ポイントツーポイントネットワーク接続を表しているかどうかを確認するには、次の手順に従います。

@Test
public void givenInterface_whenChecksIfPointToPoint_thenCorrect() {
    NetworkInterface nif = NetworkInterface.getByName("lo");

    assertFalse(nif.isPointToPoint());
}

または、仮想インターフェイスの場合:

@Test
public void givenInterface_whenChecksIfVirtual_thenCorrect() {
    NetworkInterface nif = NetworkInterface.getByName("lo");
    assertFalse(nif.isVirtual());
}

マルチキャストがサポートされているかどうかを確認するには:

@Test
public void givenInterface_whenChecksMulticastSupport_thenCorrect() {
    NetworkInterface nif = NetworkInterface.getByName("lo");

    assertTrue(nif.supportsMulticast());
}

または、通常はMACアドレスと呼ばれる物理アドレスを取得するには:

@Test
public void givenInterface_whenGetsMacAddress_thenCorrect() {
    NetworkInterface nif = NetworkInterface.getByName("lo");
    byte[] bytes = nif.getHardwareAddress();

    assertNotNull(bytes);
}

もう1つのパラメータは、このインターフェイスを介して送信できる最大パケットサイズを定義するMaximumTransmissionUnitです。

@Test
public void givenInterface_whenGetsMTU_thenCorrect() {
    NetworkInterface nif = NetworkInterface.getByName("net0");
    int mtu = nif.getMTU();

    assertEquals(1500, mtu);
}

5. 結論

この記事では、ネットワークインターフェイス、プログラムでそれらにアクセスする方法、およびそれらにアクセスする必要がある理由を示しました。

この記事で使用されている完全なソースコードとサンプルは、Githubプロジェクトで入手できます。