Utilisation des interfaces réseau en Java

1. Vue d'ensemble

Dans cet article, nous allons nous concentrer sur les interfaces réseau et comment y accéder par programme en Java.

En termes simples, une interface réseau est le point d'interconnexion entre un appareil et l'une de ses connexions réseau .

Dans le langage courant, nous les désignons par le terme de cartes d'interface réseau (NIC) - mais elles ne doivent pas toutes être de forme matérielle.

Par exemple, le populaire localhost IP 127.0.0.1 , que nous utilisons beaucoup pour tester les applications Web et réseau, est l'interface de bouclage - qui n'est pas une interface matérielle directe.

Bien sûr, les systèmes ont souvent plusieurs connexions réseau actives, telles que Ethernet filaire, WIFI, Bluetooth, etc.

En Java, la principale API que nous pouvons utiliser pour interagir directement avec eux est la classe java.net.NetworkInterface . Et donc, pour commencer rapidement, importons le package complet:

import java.net.*;

2. Pourquoi accéder aux interfaces réseau?

La plupart des programmes Java n'interagiront probablement pas directement avec eux; il existe cependant des scénarios particuliers où nous avons besoin de ce type d'accès de bas niveau.

Le plus remarquable d'entre eux est lorsqu'un système a plusieurs cartes et que vous souhaitez avoir la liberté de choisir une interface spécifique avec laquelle utiliser un socket . Dans un tel scénario, nous connaissons généralement le nom mais pas nécessairement l'adresse IP.

Normalement, lorsque nous voulons établir une connexion socket, le à une adresse de serveur spécifique:

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

De cette façon, le système choisit une adresse locale appropriée, s'y lie et communique avec le serveur via son interface réseau. Cependant, cette approche ne nous permet pas de choisir la nôtre.

Nous ferons une hypothèse ici; nous ne connaissons pas l'adresse mais nous connaissons le nom. Juste à des fins de démonstration, supposons que nous voulons la connexion via l'interface de bouclage, par convention, son nom est lo , au moins sur les systèmes Linux et Windows, sur OSX c'est 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));

Nous récupérons donc d'abord l'interface réseau attachée à lo , récupérons les adresses qui lui sont attachées, créons une socket, la lions à l'une des adresses énumérées que nous ne connaissons même pas au moment de la compilation, puis nous nous connectons.

Un objet NetworkInterface contient un nom et un ensemble d'adresses IP qui lui sont attribués. La liaison avec l'une de ces adresses garantira la communication via cette interface.

Cela ne dit rien de spécial sur l'API. Nous savons que si nous voulons que notre adresse locale soit localhost, le premier extrait de code suffirait si nous venons d'ajouter le code de liaison.

De plus, nous n'aurions jamais vraiment à passer par toutes les étapes puisque localhost a une adresse bien connue, 127.0.0.1 et nous pouvons facilement y lier le socket.

Cependant, dans votre cas, lo aurait peut-être pu représenter d'autres interfaces comme Bluetooth - net1 , réseau sans fil - net0 ou ethernet - eth0 . Dans de tels cas, vous ne connaissez pas l'adresse IP au moment de la compilation.

3. Récupération des interfaces réseau

Dans cette section, nous explorerons les autres API disponibles pour récupérer les interfaces disponibles. Dans la section précédente, nous n'avons vu qu'une de ces approches; la méthode statique getByName () .

Il convient de noter que la classe NetworkInterface n'a pas de constructeur public, nous ne sommes donc bien sûr pas en mesure de créer une nouvelle instance. Au lieu de cela, nous allons utiliser les API disponibles pour en récupérer une.

L'API que nous avons examinée jusqu'à présent est utilisée pour rechercher une interface réseau par le nom spécifié:

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

Il retourne null si aucun n'est pour le nom:

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

La deuxième API est getByInetAddress () , elle nécessite également que nous fournissions un paramètre connu, cette fois nous pouvons fournir l'adresse IP:

@Test public void givenIP_whenReturnsNetworkInterface_thenCorrect() { byte[] ip = new byte[] { 127, 0, 0, 1 }; NetworkInterface nif = NetworkInterface.getByInetAddress( InetAddress.getByAddress(ip)); assertNotNull(nif); }

Ou nom de l'hôte:

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

Ou si vous êtes spécifique à propos de localhost:

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

Une autre alternative est également d'utiliser explicitement l'interface de bouclage:

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

La troisième approche qui n'est disponible que depuis Java 7 est d'obtenir une interface réseau par son index:

NetworkInterface nif = NetworkInterface.getByIndex(int index);

La dernière approche consiste à utiliser l' API getNetworkInterfaces . Il renvoie une énumération de toutes les interfaces réseau disponibles dans le système. C'est à nous de récupérer les objets retournés dans une boucle, l'idiome standard utilise un List :

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

4. Paramètres d'interface réseau

Il y a beaucoup d'informations précieuses que nous pouvons obtenir de l'un après avoir récupéré son objet. L'un des plus utiles est la liste des adresses IP qui lui sont attribuées .

Nous pouvons obtenir des adresses IP à l'aide de deux API. La première API est getInetAddresses () . Il retourne une énumération d' instances InetAddress que nous pouvons traiter comme nous le jugeons approprié:

@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()); }

La deuxième API est getInterfaceAddresses () . Il renvoie une liste d' instances InterfaceAddress qui sont plus puissantes que les instances InetAddress . Par exemple, en dehors de l'adresse IP, vous pouvez être intéressé par l'adresse de diffusion:

@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()); }

Nous pouvons accéder aux paramètres réseau d'une interface au-delà du nom et des adresses IP qui lui sont attribués. Pour vérifier s'il est opérationnel:

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

Pour vérifier s'il s'agit d'une interface de bouclage:

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

Pour vérifier s'il représente une connexion réseau point à point:

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

Ou s'il s'agit d'une interface virtuelle:

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

Pour vérifier si la multidiffusion est prise en charge:

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

Ou pour récupérer son adresse physique, généralement appelée adresse MAC:

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

Un autre paramètre est l'unité de transmission maximale qui définit la plus grande taille de paquet pouvant être transmise via cette interface:

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

5. Conclusion

Dans cet article, nous avons montré les interfaces réseau, comment y accéder par programme et pourquoi nous aurions besoin d'y accéder.

Le code source complet et les exemples utilisés dans cet article sont disponibles dans le projet Github.