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.
GO TO FULL VERSION