Als we het hebben over netwerken, kunnen we niet anders dan het OSI-model noemen.

Wat dit model betreft, zijn we vandaag het meest geïnteresseerd in de transportlaag (4).

Dit is het niveau waarop we werken met gegevens die "van punt A naar punt B" gaan. De belangrijkste taak van de transportlaag is ervoor te zorgen dat een bericht op de bestemming wordt afgeleverd, met behoud van de juiste volgorde. De twee meest voorkomende transportlaagprotocollen zijn: TCP en UDP. Ze werken conceptueel op verschillende manieren, maar elk heeft zijn eigen voordelen waarmee ze specifieke problemen kunnen oplossen.

Laten we eerst eens kijken hoe TCP werkt.

TCP (Transmission Control Protocol) is een netwerkprotocol dat ervoor zorgt dat er een verbinding tussen hosts tot stand wordt gebracht voordat gegevens worden uitgewisseld.

Dit is een zeer betrouwbaar protocol, omdat het elke keer dat het een ander datapakket verzendt, moet controleren of het vorige pakket is ontvangen.

De verzonden pakketten worden geordend en als er problemen zijn met een bepaald pakket (dwz de ontvangende partij bevestigt niet dat het pakket is aangekomen), wordt het pakket opnieuw verzonden. Hierdoor is de overdrachtssnelheid relatief laag, omdat er meer tijd nodig is voor de strikte monitoring en voor het zorgen voor de juiste bestelling.

Hier komt zijn "broer", het UDP-protocol, om de hoek kijken. In tegenstelling tot TCP geeft UDP niet echt om de volgorde en status van elk pakket. Het verstuurt eenvoudig gegevens zonder ontvangstbevestiging. Bovendien brengt het geen verbinding tot stand en is het op geen enkele manier afhankelijk van een verbindingsstatus.

Het doel is simpelweg om gegevens naar een adres te sturen. En dit geeft aanleiding tot het grootste nadeel van het protocol, lage betrouwbaarheid, omdat het eenvoudig stukjes gegevens kan verliezen. Bovendien moet de ontvanger erop voorbereid zijn dat de gegevens verkeerd kunnen aankomen. Dat gezegd hebbende, het protocol heeft ook een voordeel, een hogere overdrachtssnelheid, vanwege het feit dat het protocol beperkt is tot het verzenden van gegevens.

Er zijn ook verschillen in de manier waarop de gegevens zelf worden verzonden. In TCP worden gegevens gestreamd, wat betekent dat de gegevens geen grenzen hebben. In UDP worden gegevens verzonden als datagrammen en hebben ze grenzen, en de ontvanger controleert de integriteit van de gegevens, maar alleen als het bericht met succes is ontvangen.

Laten we samenvatten:

TCP is een betrouwbaar en nauwkeurig protocol dat gegevensverlies voorkomt. Een bericht zal altijd met maximale nauwkeurigheid worden afgeleverd, of helemaal niet worden afgeleverd. De ontvanger heeft geen logica nodig voor het ordenen van gegevens, aangezien binnenkomende gegevens al worden geordend. UDP is niet zo betrouwbaar, maar het is een sneller protocol voor gegevensoverdracht. De verzendende en ontvangende partijen hebben wat extra logica nodig om met dit protocol te kunnen werken. Maar laten we eens kijken hoe het werkt aan de hand van het voorbeeld van een computerspel of mobiel spel dat via het netwerk wordt gespeeld. Het maakt ons misschien niet meer uit wat er 5 seconden geleden had moeten aankomen, en we kunnen een paar pakketten overslaan als ze niet op tijd aankomen - het spel kan vertragen, maar je kunt nog steeds spelen!

Om in Java te werken met datagrammen die via UDP worden verzonden, gebruiken we objecten van de klassen DatagramSocket en DatagramPacket .

Om gegevens uit te wisselen, maken de zender en ontvanger datagram-sockets, dwz instanties van de klasse DatagramSocket . De klasse heeft verschillende constructors. Het verschil tussen beide is waar de gemaakte socket verbinding zal maken:

DatagramSocket () Maakt verbinding met elke beschikbare poort op de lokale computer
DatagramSocket (int-poort) Maakt verbinding met de opgegeven poort op de lokale computer
DatagramSocket (int-poort, InetAddress-adres) Maakt verbinding met de opgegeven poort op een adres op de lokale machine (addr)

De klasse bevat veel methoden voor toegang tot en beheer van de socketparameters (we zullen ze later bekijken), evenals methoden voor het ontvangen en verzenden van datagrammen:

verzenden (DatagramPacket-pakket) Verzendt datagrammen verpakt in pakketten
ontvangen (DatagramPacket-pakket) Ontvangt datagrammen verpakt in pakketten

DatagramPacket is een klasse die een datagrampakket vertegenwoordigt. Datagrampakketten worden gebruikt om een ​​verbindingsloze pakketbezorgservice te implementeren. Elk bericht wordt uitsluitend op basis van de informatie in dat pakket van de ene machine naar de andere gestuurd. Meerdere pakketten die van de ene machine naar de andere worden verzonden, kunnen verschillend worden gerouteerd en kunnen in willekeurige volgorde aankomen. Levering van pakketten is niet gegarandeerd.

constructeurs:

DatagramPacket(byte[] buf, int lengte) Creëert een DatagramPacket om pakketten van lengte length te accepteren .
DatagramPacket(byte[] buf, int lengte, InetAddress adres, int poort) Creëert een datagrampakket om pakketten van lengtelengte naar het gespecificeerde poortnummer op de gespecificeerde host te sturen.
DatagramPacket(byte[] buf, int offset, int lengte) Creëert een DatagramPacket om pakketten van lengte length te accepteren , waarbij een offset in de buffer wordt gespecificeerd.
DatagramPacket(byte[] buf, int offset, int lengte, InetAddress adres, int poort) Creëert een datagrampakket om pakketten van lengtelengte met offset- offset naar het opgegeven poortnummer op de opgegeven host te verzenden.
DatagramPacket(byte[] buf, int offset, int lengte, SocketAddress adres) Creëert een datagrampakket om pakketten van lengtelengte met offset- offset naar het opgegeven poortnummer op de opgegeven host te verzenden.
DatagramPacket(byte[] buf, int lengte, SocketAddress adres) Creëert een datagrampakket om pakketten van lengtelengte naar het gespecificeerde poortnummer op de gespecificeerde host te sturen.

We herinneren eraan dat de UDP-benadering geen verbinding tot stand brengt. De pakketten worden verzonden in de hoop dat de ontvanger ze verwacht. Maar u kunt een verbinding tot stand brengen met behulp van de methode connect(InetAddress addr, int port) van de klasse DatagramSocket .

Er wordt een eenrichtingsverbinding tot stand gebracht met de host op basis van een adres en poort: om datagrammen te verzenden of te ontvangen. De verbinding kan worden verbroken met behulp van de methode disconnect() .

Laten we proberen servercode te schrijven op basis van DatagramSocket om gegevens te ontvangen:


import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

class Recipient {

   public static void main(String[] args) {
       try {
           DatagramSocket ds = new DatagramSocket(1050);

           while (true) {
               DatagramPacket pack = new DatagramPacket(new byte[5], 5);
               ds.receive(pack);
               System.out.println(new String(pack.getData()));
           }
       } catch (IOException e) {
           e.printStackTrace();
       }
   }
}

We maken een DatagramSocket- object om te luisteren op poort 1050. Wanneer het een bericht ontvangt, drukt het het af naar de console. We zullen het woord "Hallo" verzenden, dus beperken we de buffergrootte tot vijf bytes.

Nu gaan we de afzenderklasse maken:


import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

class Sender {
   private String host;
   private int port;

   Sender(String host, int port) {
       this.host = host;
       this.port = port;
   }

   private void sendMessage(String mes) {
       try {
           byte[] data = mes.getBytes();
           InetAddress address = InetAddress.getByName(host);
           DatagramPacket pack = new DatagramPacket(data, data.length, address, port);
           DatagramSocket ds = new DatagramSocket();
           ds.send(pack);
           ds.close();
       } catch (IOException e) {
           System.err.println(e);
       }
   }

   public static void main(String[] args) {
   Sender sender = new Sender("localhost", 1050);
   String message = "Hello";

   Timer timer = new Timer();
   timer.scheduleAtFixedRate(new TimerTask() {
       @Override
       public void run() {
           sender.sendMessage(message);
       }
   }, 1000, 1000);
}

}

In de methode sendMessage maken we een DatagramPacket en DatagramSocket en verzenden we ons bericht. Merk op dat de methode close() wordt gebruikt om de DatagramSocket te sluiten nadat het bericht is verzonden.

Elke seconde geeft de console van de ontvanger het inkomende "Hallo"-bericht weer dat door de afzender is verzonden. Dit betekent dat onze communicatie allemaal correct werkt.