Når vi snakker om nettverk, kan vi ikke unngå å nevne OSI-modellen.

Når det gjelder denne modellen, er vi i dag mest interessert i transportlaget (4).

Dette er nivået vi jobber med data som beveger seg "fra punkt A til punkt B". Hovedoppgaven til transportlaget er å sørge for at en melding leveres til destinasjonen, samtidig som den opprettholder riktig rekkefølge. De to vanligste transportlagsprotokollene er: TCP og UDP. De fungerer konseptuelt på forskjellige måter, men hver har sine egne fordeler som lar dem løse spesifikke problemer.

La oss først se på hvordan TCP fungerer.

TCP (Transmission Control Protocol) er en nettverksprotokoll som sikrer at en forbindelse mellom verter etableres før data utveksles.

Dette er en veldig pålitelig protokoll, fordi hver gang den sender en annen datapakke, må den sjekke at den forrige pakken ble mottatt.

De overførte pakkene bestilles, og hvis det er problemer med en bestemt pakke (dvs. at mottaker ikke bekrefter at pakken har kommet), så sendes pakken på nytt. Som et resultat er overføringshastigheten relativt lav, fordi det kreves mer tid for den strenge overvåkingen og for å sikre riktig bestilling.

Det er her dens "bror", UDP-protokollen, kommer inn. I motsetning til TCP, bryr ikke UDP seg egentlig om rekkefølgen og statusen til hver pakke. Den sender ganske enkelt data uten leveringsbekreftelse. Dessuten oppretter den ingen tilkobling og er ikke avhengig av en tilkoblingsstatus på noen måte.

Hensikten er ganske enkelt å sende data til en adresse. Og dette gir opphav til protokollens største ulempe, lav pålitelighet, siden den rett og slett kan miste biter av data. I tillegg må mottakeren være forberedt på at dataene kan komme ut av funksjon. Når det er sagt, har protokollen også en fordel, en høyere overføringshastighet, på grunn av at protokollen er begrenset til å sende data.

Det er også forskjeller i hvordan selve dataene overføres. I TCP streames data, noe som betyr at dataene ikke har noen grenser. I UDP overføres data som datagrammer og har grenser, og mottakeren sjekker integriteten til dataene, men bare hvis meldingen er vellykket mottatt.

La oss oppsummere:

TCP er en pålitelig og nøyaktig protokoll som forhindrer tap av data. En melding vil alltid bli levert med maksimal nøyaktighet, eller ikke levert i det hele tatt. Mottakeren trenger ikke logikk for å bestille data, siden innkommende data allerede vil være bestilt. UDP er ikke like pålitelig, men det er en raskere dataoverføringsprotokoll. Sendende og mottakende parter trenger litt ekstra logikk for å kunne jobbe med denne protokollen. Men la oss ta en titt på hvordan det fungerer ved å bruke eksempelet på et dataspill eller mobilspill som spilles over nettverket. Vi bryr oss kanskje ikke lenger om hva som skulle ha kommet for 5 sekunder siden, og vi kan hoppe over et par pakker hvis de ikke kommer i tide – spillet kan ligge etter, men du kan fortsatt spille!

I Java, for å jobbe med datagrammer som overføres over UDP, bruker vi objekter av klassene DatagramSocket og DatagramPacket .

For å utveksle data oppretter avsender og mottaker datagram-sockets, dvs. instanser av DatagramSocket -klassen. Klassen har flere konstruktører. Forskjellen mellom dem er hvor den opprettede kontakten kobles til:

DatagramSocket () Kobles til enhver tilgjengelig port på den lokale maskinen
DatagramSocket (int port) Kobles til den angitte porten på den lokale maskinen
DatagramSocket (int port, InetAddress-adresse) Kobler til den angitte porten på en adresse på den lokale maskinen (addr)

Klassen inneholder mange metoder for å få tilgang til og administrere socket-parametrene (vi vil se på dem litt senere), samt metoder for å motta og sende datagrammer:

send (DatagramPacket pack) Sender datagrammer pakket inn i pakker
motta (DatagramPacket-pakke) Mottar datagrammer pakket inn i pakker

DatagramPacket er en klasse som representerer en datagrampakke. Datagrampakker brukes til å implementere en forbindelsesløs pakkeleveringstjeneste. Hver melding blir rutet fra en maskin til en annen basert utelukkende på informasjonen i den pakken. Flere pakker sendt fra en maskin til en annen kan rutes forskjellig og kan ankomme i hvilken som helst rekkefølge. Levering av pakker er ikke garantert.

Konstruktører:

DatagramPacket(byte[] buf, int lengde) Oppretter en DatagramPacket for å akseptere pakker med lengdelengde .
DatagramPacket(byte[] buf, int lengde, InetAddress-adresse, int port) Oppretter en datagrampakke for å sende pakker med lengdelengde til det angitte portnummeret på den angitte verten.
DatagramPacket(byte[] buf, int offset, int lengde) Oppretter en DatagramPacket for å akseptere pakker med lengdelengde , og spesifiserer en offset i bufferen.
DatagramPacket(byte[] buf, int offset, int lengde, InetAddress-adresse, int port) Oppretter en datagrampakke for å sende pakker med lengdelengde med offsetoffset til det angitte portnummeret på den angitte verten.
DatagramPacket(byte[] buf, int offset, int lengde, SocketAddress-adresse) Oppretter en datagrampakke for å sende pakker med lengdelengde med offsetoffset til det angitte portnummeret på den angitte verten.
DatagramPacket(byte[] buf, int lengde, SocketAddress-adresse) Oppretter en datagrampakke for å sende pakker med lengdelengde til det angitte portnummeret på den angitte verten.

Vi husker at UDP-tilnærmingen ikke etablerer en forbindelse. Pakkene sendes av gårde i håp om at mottakeren venter dem. Men du kan opprette en tilkobling ved å bruke connect(InetAddress addr, int port) -metoden til DatagramSocket- klassen.

En enveisforbindelse etableres med verten basert på en adresse og port: enten for å sende eller motta datagrammer. Forbindelsen kan avsluttes ved å bruke disconnect()- metoden.

La oss prøve å skrive serverkode basert på DatagramSocket for å motta data:

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

Vi lager et DatagramSocket- objekt for å lytte på port 1050. Når det mottar en melding, skriver det det ut til konsollen. Vi vil overføre ordet "Hei", så vi begrenser bufferstørrelsen til fem byte.

Nå skal vi opprette avsenderklassen:

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

}

I sendMessage- metoden lager vi en DatagramPacket og DatagramSocket , og sender meldingen vår. Merk at close()- metoden brukes til å lukke DatagramSocket etter at meldingen er sendt.

Hvert sekund viser mottakerens konsoll den innkommende "Hei"-meldingen sendt av avsenderen. Dette betyr at vår kommunikasjon fungerer som den skal.