Werken met netwerkinterfaces in Java

1. Overzicht

In dit artikel zullen we ons concentreren op netwerkinterfaces en hoe u deze programmatisch kunt openen in Java.

Simpel gezegd, een netwerkinterface is het verbindingspunt tussen een apparaat en een van zijn netwerkverbindingen.

In alledaagse taal verwijzen we ernaar met de term Network Interface Cards (NIC's) - maar ze hoeven niet allemaal hardwarevorm te zijn.

Bijvoorbeeld het populaire localhost IP 127.0.0.1, die we veel gebruiken bij het testen van web- en netwerktoepassingen, is de loopback-interface - die geen directe hardware-interface is.

Systemen hebben natuurlijk vaak meerdere actieve netwerkverbindingen, zoals bedraad ethernet, WIFI, Bluetooth, etc.

In Java is de belangrijkste API die we kunnen gebruiken om rechtstreeks met hen te communiceren de java.net.NetworkInterface klasse. Laten we dus, om snel aan de slag te gaan, het volledige pakket importeren:

importeer java.net. *;

2. Waarom toegang tot netwerkinterfaces?

De meeste Java-programma's zullen waarschijnlijk niet rechtstreeks met hen communiceren; er zijn echter speciale scenario's wanneer we dit soort toegang op laag niveau nodig hebben.

De meest opvallende hiervan is wanneer een systeem meerdere kaarten heeft en u de vrijheid om een ​​specifieke interface te kiezen om een ​​stopcontact mee te gebruiken. In een dergelijk scenario kennen we meestal de naam, maar niet noodzakelijk het IP-adres.

Normaal gesproken, wanneer we een socketverbinding willen maken met een specifiek serveradres:

Socket socket = nieuwe Socket (); socket.connect (nieuw InetSocketAddress (adres, poort));

Op deze manier kiest het systeem een ​​geschikt lokaal adres, bindt eraan en communiceert het met de server via zijn netwerkinterface. Deze benadering staat ons echter niet toe om onze eigen keuze te maken.

We zullen hier een aanname doen; we kennen het adres niet, maar we kennen de naam. Laten we voor demonstratiedoeleinden aannemen dat we de verbinding via de loopback-interface willen, volgens afspraak is de naam zie, althans op Linux- en Windows-systemen, op OSX wel lo0:

NetworkInterface nif = NetworkInterface.getByName ("lo"); Opsomming nifAddresses = nif.getInetAddresses (); Socket socket = nieuwe Socket (); socket.bind (nieuw InetSocketAddress (nifAddresses.nextElement (), 0)); socket.connect (nieuw InetSocketAddress (adres, poort));

Dus halen we de netwerkinterface op die is gekoppeld aan zie Haal eerst de adressen op die eraan zijn gekoppeld, maak een socket, bind deze aan een van de opgesomde adressen die we niet eens kennen tijdens het compileren en maak vervolgens verbinding.

EEN Netwerkinterface object bevat een naam en een reeks IP-adressen die eraan zijn toegewezen. Dus binding aan een van deze adressen garandeert communicatie via deze interface.

Dit zegt eigenlijk niets bijzonders over de API. We weten dat als we willen dat ons lokale adres localhost is, het eerste fragment voldoende zou zijn als we zojuist de bindingscode hebben toegevoegd.

Bovendien zouden we nooit echt alle verschillende stappen hoeven te doorlopen, aangezien localhost één bekend adres heeft, 127.0.0.1 en we kunnen de socket er gemakkelijk aan binden.

In uw geval zie had misschien andere interfaces zoals Bluetooth kunnen vertegenwoordigen - net1, draadloos netwerk - net0 of ethernet - eth0. In dergelijke gevallen zou u het IP-adres tijdens het compileren niet weten.

3. Netwerkinterfaces ophalen

In deze sectie zullen we de andere beschikbare API's verkennen om de beschikbare interfaces op te halen. In de vorige sectie hebben we slechts één van deze benaderingen gezien; de getByName () statische methode.

Het is vermeldenswaard dat de Netwerkinterface class heeft geen openbare constructors, dus we kunnen natuurlijk geen nieuwe instantie maken. In plaats daarvan gaan we de beschikbare API's gebruiken om er een op te halen.

De API die we tot nu toe hebben bekeken, wordt gebruikt om een ​​netwerkinterface te doorzoeken op de opgegeven naam:

@Test openbare ongeldig gegevenName_whenReturnsNetworkInterface_thenCorrect () {NetworkInterface nif = NetworkInterface.getByName ("lo"); assertNotNull (nif); }

Het keert terug nul als er geen is voor de naam:

@Test openbare ongeldig gegevenInExistentName_whenReturnsNull_thenCorrect () {NetworkInterface nif = NetworkInterface.getByName ("onbestaande_naam"); assertNull (nif); }

De tweede API is getByInetAddress (), het vereist ook dat we een bekende parameter opgeven, deze keer kunnen we het IP-adres opgeven:

@Test openbare ongeldig gegevenIP_whenReturnsNetworkInterface_thenCorrect () {byte [] ip = nieuwe byte [] {127, 0, 0, 1}; NetworkInterface nif = NetworkInterface.getByInetAddress (InetAddress.getByAddress (ip)); assertNotNull (nif); }

Of naam van de host:

@Test openbare ongeldig gegevenHostName_whenReturnsNetworkInterface_thenCorrect () {NetworkInterface nif = NetworkInterface.getByInetAddress (InetAddress.getByName ("localhost")); assertNotNull (nif); }

Of als u specifiek bent over localhost:

@Test openbare ongeldig gegevenLocalHost_whenReturnsNetworkInterface_thenCorrect () {NetworkInterface nif = NetworkInterface.getByInetAddress (InetAddress.getLocalHost ()); assertNotNull (nif); }

Een ander alternatief is ook om expliciet de loopback-interface te gebruiken:

@Test openbare ongeldig gegevenLoopBack_whenReturnsNetworkInterface_thenCorrect () {NetworkInterface nif = NetworkInterface.getByInetAddress (InetAddress.getLoopbackAddress ()); assertNotNull (nif); }

De derde benadering die pas sinds Java 7 beschikbaar is, is om een ​​netwerkinterface te krijgen op basis van de index:

NetworkInterface nif = NetworkInterface.getByIndex (int index);

De laatste benadering omvat het gebruik van de getNetworkInterfaces API. Het retourneert een Opsomming van alle beschikbare netwerkinterfaces in het systeem. Het is aan ons om de geretourneerde objecten in een lus op te halen, het standaard idioom gebruikt een Lijst:

Opsommingsnetten = NetworkInterface.getNetworkInterfaces (); for (NetworkInterface nif: Collections.list (nets)) {// doe iets met de netwerkinterface}

4. Netwerkinterfaceparameters

Er is veel waardevolle informatie die we kunnen krijgen nadat we het object hebben opgehaald. Een van de handigste is de lijst met IP-adressen die eraan zijn toegewezen.

We kunnen IP-adressen krijgen met behulp van twee API's. De eerste API is getInetAddresses (). Het retourneert een Opsomming van InetAddress gevallen die we naar eigen goeddunken kunnen verwerken:

@Test openbare ongeldige gegevenInterface_whenReturnsInetAddresses_thenCorrect () {NetworkInterface nif = NetworkInterface.getByName ("lo"); Opsomming addressEnum = nif.getInetAddresses (); InetAddress adres = addressEnum.nextElement (); assertEquals ("127.0.0.1", address.getHostAddress ()); }

De tweede API is getInterfaceAddresses (). Het retourneert een Lijst van InterfaceAddress gevallen die krachtiger zijn dan InetAddress gevallen. Afgezien van het IP-adres bent u bijvoorbeeld mogelijk geïnteresseerd in het uitzendadres:

@Test openbare ongeldige gegevenInterface_whenReturnsInterfaceAddresses_thenCorrect () {NetworkInterface nif = NetworkInterface.getByName ("lo"); Lijst addressEnum = nif.getInterfaceAddresses (); InterfaceAddress adres = 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 ()); }

We hebben toegang tot netwerkparameters over een interface buiten de naam en IP-adressen die eraan zijn toegewezen. Om te controleren of het actief is:

@Test openbare ongeldigheid gegevenInterface_whenChecksIfUp_thenCorrect () {NetworkInterface nif = NetworkInterface.getByName ("lo"); bewerenTrue (nif.isUp ()); }

Om te controleren of het een loopback-interface is:

@Test openbare ongeldige gegevenInterface_whenChecksIfLoopback_thenCorrect () {NetworkInterface nif = NetworkInterface.getByName ("lo"); assertTrue (nif.isLoopback ()); }

Om te controleren of het een point-to-point netwerkverbinding vertegenwoordigt:

@Test openbare ongeldigheid gegevenInterface_whenChecksIfPointToPoint_thenCorrect () {NetworkInterface nif = NetworkInterface.getByName ("lo"); assertFalse (nif.isPointToPoint ()); }

Of als het een virtuele interface is:

@Test openbare ongeldige gegevenInterface_whenChecksIfVirtual_thenCorrect () {NetworkInterface nif = NetworkInterface.getByName ("lo"); assertFalse (nif.isVirtual ()); }

Controleren of multicasting wordt ondersteund:

@Test openbare ongeldige gegevenInterface_whenChecksMulticastSupport_thenCorrect () {NetworkInterface nif = NetworkInterface.getByName ("lo"); assertTrue (nif.supportsMulticast ()); }

Of om het fysieke adres op te halen, meestal het MAC-adres genoemd:

@Test openbare ongeldige gegevenInterface_whenGetsMacAddress_thenCorrect () {NetworkInterface nif = NetworkInterface.getByName ("lo"); byte [] bytes = nif.getHardwareAddress (); assertNotNull (bytes); }

Een andere parameter is de maximale transmissie-eenheid die de grootste pakketgrootte definieert die via deze interface kan worden verzonden:

@Test openbare ongeldige gegevenInterface_whenGetsMTU_thenCorrect () {NetworkInterface nif = NetworkInterface.getByName ("net0"); int mtu = nif.getMTU (); assertEquals (1500, mtu); }

5. Conclusie

In dit artikel hebben we netwerkinterfaces laten zien, hoe u deze programmatisch kunt openen en waarom we er toegang toe zouden moeten hebben.

De volledige broncode en voorbeelden die in dit artikel worden gebruikt, zijn beschikbaar in het Github-project.