Когато говорим за работа в мрежа, няма How да не споменем OSI модела.

От гледна точка на този модел днес най-голям интерес ни интересува транспортният слой (4).

Това е нивото, на което работим с данни, движещи се „от точка А до точка Б“. Основната задача на транспортния слой е да гарантира, че съобщението е доставено до дестинацията, като същевременно поддържа правилната последователност. Двата най-често срещани протокола на транспортния слой са: TCP и UDP. Те работят концептуално по различни начини, но всеки има своите предимства, които им позволяват да решават конкретни проблеми.

Първо, нека да разгледаме How работи TCP.

TCP (Transmission Control Protocol) е мрежов протокол, който гарантира, че връзката между хостовете е установена преди обмен на данни.

Това е много надежден протокол, тъй като всеки път, когато изпраща друг пакет данни, той трябва да провери дали предишният пакет е получен.

Изпратените пакети се подреждат и ако има проблеми с даден пакет (т.е. приемащата страна не потвърди, че пакетът е пристигнал), тогава пакетът се изпраща отново. В резултат на това скоростта на трансфер е относително ниска, тъй като е необходимо повече време за стриктно наблюдение и за осигуряване на правилното поръчване.

Тук се намесва неговият "брат", протоколът UDP. За разлика от TCP, UDP не се интересува от реда и състоянието на всеки пакет. Той просто изпраща данни без потвърждение за доставка. Нещо повече, той не установява връзка и по ниHowъв начин не зависи от състоянието на връзката.

Целта му е просто да изпрати данни до address. И това води до основния недостатък на протокола, ниската надеждност, тъй като той може просто да загуби части от данни. Освен това получателят трябва да е подготвен за факта, че данните могат да пристигнат неправилно. Въпреки това, протоколът има и предимство, по-висока скорост на трансфер, поради факта, че протоколът е ограничен до изпращане на данни.

Има и разлики в начина на предаване на самите данни. В TCP данните се предават поточно, което означава, че данните нямат граници. При UDP данните се предават като дейтаграми и имат граници, а получателят проверява целостта на данните, но само ако съобщението е получено успешно.

Нека обобщим:

TCP е надежден и точен протокол, който предотвратява загуба на данни. Едно съобщение винаги ще бъде доставено с максимална точност or изобщо няма да бъде доставено. Получателят не се нуждае от логика за подреждане на данни, тъй като входящите данни вече ще бъдат подредени. UDP не е толкова надежден, но е по-бърз протокол за пренос на данни. Изпращащата и получаващата страна се нуждаят от допълнителна логика, за да работят с този протокол. Но нека да разгледаме How работи на примера на компютърна игра or мобилна игра, играна по мрежата. Може вече да не ни интересува Howво е трябвало да пристигне преди 5 секунди и можем да пропуснем няколко пакета, ако не пристигнат навреме — играта може да закъснее, но все още можете да играете!

В Java, за да работим с дейтаграми, предавани по UDP, използваме обекти от класовете DatagramSocket и DatagramPacket .

За да обменят данни, подателят и получателят създават дейтаграмни гнезда, т.е. екземпляри на класа DatagramSocket . Класът има няколко конструктора. Разликата между тях е къде ще се свърже създаденият сокет:

DatagramSocket () Свързва се към всеки наличен порт на локалната машина
DatagramSocket (вътрешен порт) Свързва се към посочения порт на локалната машина
DatagramSocket(int порт, InetAddress address) Свързва се към посочения порт на address на локалната машина (addr)

Класът съдържа много методи за достъп и управление на параметрите на сокета (ще ги разгледаме малко по-късно), Howто и методи за получаване и изпращане на дейтаграми:

изпрати (пакет DatagramPacket) Изпраща дейтаграми, пакетирани в пакети
получаване (пакет DatagramPacket) Получава дейтаграми, пакетирани в пакети

DatagramPacket е клас, който представлява пакет от дейтаграми. Пакетите с дейтаграми се използват за прилагане на услуга за доставка на пакети без връзка. Всяко съобщение се насочва от една машина към друга въз основа единствено на информацията, съдържаща се в този пакет. Множество пакети, изпратени от една машина на друга, могат да бъдат маршрутизирани по различен начин и да пристигнат в произволен ред. Доставката на пакети не е гарантирана.

Конструктори:

DatagramPacket(byte[] buf, int дължина) Създава DatagramPacket за приемане на пакети с дължина length .
DatagramPacket(byte[] buf, int дължина, InetAddress address, int порт) Създава дейтаграмен пакет за изпращане на пакети с дължина дължина до посочения номер на порт на посочения хост.
DatagramPacket(byte[] buf, int отместване, int дължина) Създава DatagramPacket за приемане на пакети с дължина length , като указва отместване в буфера.
DatagramPacket(byte[] buf, int отместване, int дължина, InetAddress address, int порт) Създава пакет с дейтаграма за изпращане на пакети с дължина дължина с отместване отместване до посочения номер на порт на посочения хост.
DatagramPacket(byte[] buf, int offset, int length, address на SocketAddress) Създава пакет с дейтаграма за изпращане на пакети с дължина дължина с отместване отместване до посочения номер на порт на посочения хост.
DatagramPacket(byte[] buf, int дължина, address на SocketAddress) Създава дейтаграмен пакет за изпращане на пакети с дължина дължина до посочения номер на порт на посочения хост.

Припомняме, че UDP подходът не установява връзка. Пакетите се изпращат с надеждата, че получателят ги очаква. Но можете да установите връзка с помощта на метода connect(InetAddress addr, int port) на класа DatagramSocket .

Установява се еднопосочна връзка с хоста въз основа на address и порт: за изпращане or получаване на дейтаграми. Връзката може да бъде прекъсната с помощта на метода disconnect() .

Нека се опитаме да напишем сървърен code, базиран на DatagramSocket , за да получаваме данни:

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

Създаваме DatagramSocket обект за слушане на порт 1050. Когато получи съобщение, той го отпечатва на конзолата. Ще предадем думата "Hello", така че ограничаваме размера на буфера до пет byteа.

Сега ще създадем класа на изпращача:

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

}

В метода sendMessage създаваме DatagramPacket и DatagramSocket и изпращаме нашето съобщение. Имайте предвид, че методът close() се използва за затваряне на DatagramSocket след изпращане на съобщението.

Всяка секунда конзолата на получателя показва входящото съобщение „Здравей“, изпратено от подателя. Това означава, че цялата ни комуникация работи правилно.