Javaでネットワークインターフェースを操作する

Javaでのネットワークインターフェイスの使用

1. 概要

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

簡単に言えば、network interface is the point of interconnection between a device and any of its network connectionsです。

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

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

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

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

import java.net.*;

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

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

これらの中で最も優れているのは、システムに複数のカードがあり、freedom to choose a specific interface to use a socket withが必要な場合です。 このようなシナリオでは、通常、名前はわかっていますが、必ずしもIPアドレスはわかっていません。

通常、特定のサーバーアドレスへのソケット接続を行いたい場合:

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

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

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

NetworkInterface nif = NetworkInterface.getByName("lo");
Enumeration 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にしたい場合、バインディングコードを追加しただけで最初のスニペットで十分であることがわかります。

さらに、ローカルホストには1つの既知のアドレス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);
}

または、localhostに特定の場合:

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

    assertNotNull(nif);
}

また、ループバックインターフェイスを明示的に使用することもできます。

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

    assertNotNull(nif);
}

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

NetworkInterface nif = NetworkInterface.getByIndex(int index);

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

Enumeration nets = NetworkInterface.getNetworkInterfaces();

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

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

オブジェクトを取得した後に取得できる貴重な情報がたくさんあります。 One of the most useful is the list of IP addresses assigned to it

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

@Test
public void givenInterface_whenReturnsInetAddresses_thenCorrect()  {
    NetworkInterface nif = NetworkInterface.getByName("lo");
    Enumeration 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 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つのパラメーターは、このインターフェイスを介して送信できる最大パケットサイズを定義するMaximum Transmission Unitです。

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

    assertEquals(1500, mtu);
}

5. 結論

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

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