Amikor hálózatépítésről beszélünk, nem hagyhatjuk figyelmen kívül az OSI modellt.

E modell szempontjából ma leginkább a szállítási réteg érdekel minket (4).

Ezen a szinten dolgozunk az "A pontból B pontba" mozgó adatokkal. A szállítási réteg fő feladata annak biztosítása, hogy az üzenet a célállomáshoz kerüljön a megfelelő sorrend megtartása mellett. A két leggyakoribb szállítási réteg protokoll: TCP és UDP. Koncepcionálisan különböző módon működnek, de mindegyiknek megvannak a maga előnyei, amelyek lehetővé teszik számukra, hogy konkrét problémákat oldjanak meg.

Először is nézzük meg, hogyan működik a TCP.

A TCP (Transmission Control Protocol) egy hálózati protokoll, amely biztosítja, hogy a gazdagépek közötti kapcsolat létrejöjjön az adatcsere előtt.

Ez egy nagyon megbízható protokoll, mert minden alkalommal, amikor újabb adatcsomagot küld, ellenőriznie kell, hogy az előző csomagot megkapta-e.

A továbbított csomagok sorrendje megtörténik, és ha probléma adódik egy adott csomaggal (vagyis a fogadó fél nem igazolja vissza, hogy a csomag megérkezett), akkor a csomag újraküldésre kerül. Ennek eredményeként az átviteli sebesség viszonylag alacsony, mert több időre van szükség a szigorú ellenőrzéshez és a helyes rendelés biztosításához.

Itt lép be a "testvére", az UDP protokoll. A TCP-vel ellentétben az UDP nem igazán törődik az egyes csomagok sorrendjével és állapotával. Egyszerűen elküldi az adatokat szállítási visszaigazolás nélkül. Ráadásul nem hoz létre kapcsolatot, és semmilyen módon nem függ a kapcsolat állapotától.

Célja egyszerűen az, hogy adatokat küldjön egy címre. És ebből adódik a protokoll fő hátránya, az alacsony megbízhatóság, mivel egyszerűen elveszíthet adatdarabokat. Emellett a címzettnek fel kell készülnie arra, hogy az adatok soron kívül érkezhetnek. Ennek ellenére a protokollnak van egy előnye is, a nagyobb átviteli sebesség, mivel a protokoll adatküldésre korlátozódik.

Az adatok továbbításának módjában is vannak különbségek. A TCP-ben az adatok streamingre kerülnek, ami azt jelenti, hogy az adatoknak nincsenek határai. Az UDP-ben az adatok datagramokként kerülnek továbbításra, és vannak határai, és a címzett ellenőrzi az adatok sértetlenségét, de csak akkor, ha az üzenet sikeresen megérkezett.

Összefoglaljuk:

A TCP egy megbízható és pontos protokoll, amely megakadályozza az adatvesztést. Az üzeneteket mindig maximális pontossággal kézbesítjük, vagy egyáltalán nem kézbesítjük. A címzettnek nincs szüksége logikára az adatok megrendeléséhez, mivel a beérkező adatok már megrendelésre kerülnek. Az UDP nem olyan megbízható, de gyorsabb adatátviteli protokoll. A küldő és fogadó félnek további logikára van szüksége ahhoz, hogy ezzel a protokollal dolgozhasson. De nézzük meg, hogyan működik ez egy számítógépes játék vagy a hálózaton keresztül játszott mobiljáték példáján. Lehet, hogy már nem törődünk azzal, hogy minek kellett volna megérkeznie 5 másodperccel ezelőtt, és néhány csomagot kihagyhatunk, ha nem érkeznek meg időben – előfordulhat, hogy a játék csúszik, de továbbra is játszhat!

A Java-ban az UDP-n keresztül továbbított datagramokkal való munkához a DatagramSocket és DatagramPacket osztályok objektumait használjuk .

Az adatcseréhez a küldő és a fogadó datagram socketeket hoz létre, azaz a DatagramSocket osztály példányait. Az osztálynak több konstruktora is van. A különbség közöttük az, hogy a létrehozott aljzat hova csatlakozik:

DatagramSocket () Csatlakozik a helyi gép bármely elérhető portjához
DatagramSocket (int port) Csatlakozik a helyi gép megadott portjához
DatagramSocket(int port, InetAddress cím) Csatlakozik a megadott porthoz a helyi gépen lévő címen (addr)

Az osztály számos módszert tartalmaz a socket paraméterek eléréséhez és kezeléséhez (kicsit később megnézzük őket), valamint a datagramok fogadásának és küldésének módszereit:

küldés (DatagramPacket csomag) Csomagokba csomagolt datagramokat küld
fogadni (DatagramPacket csomag) Csomagokba csomagolt datagramokat fogad

A DatagramPacket egy adatgramcsomagot képviselő osztály. A Datagram-csomagokat a kapcsolat nélküli csomagkézbesítési szolgáltatás megvalósítására használják. Minden üzenetet az egyik gépről a másikra irányítanak, kizárólag az adott csomagban található információk alapján. Az egyik gépről a másikra küldött több csomag eltérő módon irányítható, és bármilyen sorrendben érkezhet. A csomagok kézbesítése nem garantált.

Kivitelezők:

DatagramPacket(byte[] buf, int hosszúság) Létrehoz egy DatagramPacket-et a hosszúságú csomagok elfogadásához .
DatagramPacket(byte[] buf, int hossz, InetAddress cím, int port) Datagram-csomagot hoz létre, amely hosszúságú csomagokat küld a megadott portszámra a megadott gazdagépen.
DatagramPacket(byte[] buf, int offset, int long) Létrehoz egy DatagramPacket-et a hosszúságú csomagok elfogadásához , és megad egy eltolást a pufferben.
DatagramPacket(byte[] buf, int offset, int hossz, InetAddress cím, int port) Datagram-csomagot hoz létre, amely hosszúságú , eltolásos csomagokat küld a megadott portszámra a megadott gazdagépen.
DatagramPacket(byte[] buf, int offset, int long, SocketAddress cím) Datagram-csomagot hoz létre, amely hosszúságú , eltolásos csomagokat küld a megadott portszámra a megadott gazdagépen.
DatagramPacket(byte[] buf, int hosszúság, SocketAddress cím) Datagram-csomagot hoz létre, amely hosszúságú csomagokat küld a megadott portszámra a megadott gazdagépen.

Emlékeztetünk arra, hogy az UDP megközelítés nem hoz létre kapcsolatot. A csomagokat abban a reményben küldik el, hogy a címzett várja őket. De kapcsolatot létesíthet a DatagramSocket osztály connect(InetAddress addr, int port) metódusával .

Egyirányú kapcsolat jön létre a gazdagéppel cím és port alapján: datagramok küldésére vagy fogadására. A kapcsolat megszakítható a disconnect() metódussal.

Próbáljunk meg a DatagramSocket alapján szerverkódot írni az adatok fogadásához:

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

Létrehozunk egy DatagramSocket objektumot a figyeléshez a 1050-es porton. Amikor üzenetet kap, kinyomtatja a konzolra. A „Hello” szót továbbítjuk, ezért a puffer méretét öt bájtra korlátozzuk.

Most létrehozzuk a feladó osztályt:

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

}

A sendMessage metódusban létrehozunk egy DatagramPacket-et és DatagramSocket-et , és elküldjük üzenetünket. Vegye figyelembe, hogy a close() metódus a DatagramSocket bezárására szolgál az üzenet elküldése után.

A címzett konzolja másodpercenként megjeleníti a feladó által küldött „Hello” üzenetet. Ez azt jelenti, hogy a kommunikációnk megfelelően működik.