Condivisione della tecnologia

【JavaEE】Programmazione di rete——UDP

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Inserisci qui la descrizione dell'immagine
🤡🤡🤡个人主页🤡🤡🤡
🤡🤡🤡JavaEE专栏🤡🤡🤡

1. Presa del datagramma (UDP)

1.1 Caratteristiche

  1. Senza connessione: non è necessario stabilire un canale dedicato prima che i dati vengano trasmessi. Ogni pacchetto di dati viene inviato in modo indipendente e sceglie il proprio percorso per raggiungere la destinazione. Proprio come quando si inviano le informazioni, è necessario inviare solo le informazioni e l'altra parte no bisogno di riceverlo.
  2. Trasmissione inaffidabile: quando si trasmettono dati, non è necessario prestare attenzione al fatto che l'altra parte li abbia ricevuti, è sufficiente inviarli.
  3. Orientato al flusso di dati: l'unità base della trasmissione dei dati è ogni datagramma UDP. Dopo la lettura e la scrittura è possibile leggere e scrivere solo un datagramma UDP completo.
  4. Full-duplex: è possibile la comunicazione bidirezionale su un collegamento.

1.2 Codifica

Le API Socket sono tutte fornite dal sistema. Le API fornite da sistemi diversi sono diverse, ma queste API di sistema sono ulteriormente incapsulate in Java.
L'API socket in UDP si concentra su due classi: DatagramSocket e DatagramPacket

1.2.1DatagrammaSocket

La funzione di questa classe può essere considerata come un telecomando per il "comando della scheda di rete", cioè operazioni di lettura e scrittura sulla scheda di rete, che possono essere intese come lettura e scrittura come file.
Sono previsti diversi metodi:
Inserisci qui la descrizione dell'immagine

1.2.2DatagrammaPacchetto

Questa classe descrive i datagrammi UDP. Un oggetto DatagramPacket è equivalente a un datagramma UDP. Una volta inviato e ricevuto una volta, viene trasmesso un oggetto DatagramPacket.

1.2.3 Implementare un server eco UDP (24*7).

Eco: il client invia richieste diverse al server e il server restituisce risposte diverse. Ma l'eco qui è ciò che il client richiede al server e il server risponde senza alcun calcolo o logica aziendale.

public class udpEchoServer {
    public DatagramSocket socket = null;
    public udpEchoServer(int port) throws SocketException {
        socket = new DatagramSocket(port);
    }
    public void  start() throws IOException {
        System.out.println("服务器启动!!!");
        while (true) {
            //接受客户端请求
            DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);
            socket.receive(requestPacket);
            //为了更好处理数据并方便打印,将接受的数据转化为字符串操作
            String request = new String(requestPacket.getData(),0,requestPacket.getLength());
            //处理客户端的请求(算术计算或者业务逻辑)
            String response = this.process(request);
            //将处理完的请求返还给客户端
            DatagramPacket resposePacket = new DatagramPacket(response.getBytes(),0,response.getBytes().length,
                    requestPacket.getSocketAddress());
            socket.send(resposePacket);
            //打印客户端的ip地址端口号和接收客户端的数据以及处理完客户端后的数据
            System.out.printf("[%s:%d] req = %s,resp = %sn",requestPacket.getAddress(),requestPacket.getPort(),
                    request,response);
        }
    }
    public String process(String request) {
        return request;
    }

    public static void main(String[] args) throws IOException {
        udpEchoServer udpEchoServer = new udpEchoServer(9999);
        udpEchoServer.start();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

Inserisci qui la descrizione dell'immagine
L'oggetto DatagramPacket rappresenta un datagramma. Un datagramma UDP è composto da un'intestazione e un payload. L'indirizzo IP e il numero di porta nell'intestazione sono attributi della classe DatagramPacket, ma la classe del payload non viene fornita, quindi deve farlo il programmatore. se stesso, quindi, proprio come un monaco che chiede l'elemosina, devi fornire una ciotola per l'elemosina, e poi ogni famiglia mette il cibo nella ciotola. Poiché l'essenza del datagramma è costituita da dati binari, ho fornito un array di byte come carico utile Memorizzazione dei dati.
Inserisci qui la descrizione dell'immagine
I dati ricevuti dal client devono essere restituiti al client dopo essere stati elaborati dal server, quindi è necessario creare un oggetto DatagramPacket per archiviare i dati elaborati dal server, quindi il server lo invia al client. Al momento, l'oggetto DatagramPacket non ha bisogno di fornire uno spazio vuoto. Basta inserire i dati elaborati in questo oggetto Poiché l'indirizzo IP e il numero di porta del client vengono registrati quando si ricevono i dati, solo l'indirizzo IP e il numero di porta del client vengono registrati quando lo si invia al client. È necessario ottenere l'indirizzo IP e il numero di porta del client tramite requestPacket.getSocketAddress().
Inserisci qui la descrizione dell'immagine
Poiché il server è fisso, è possibile impostare direttamente il numero di porta. Il numero di porta viene creato all'avvio del server.
Perché ho bisogno di un indirizzo IP con numero di porta?
Per ottenere una comunicazione di successo tra le due parti, devono essere presenti questi quattro indicatori principali:
Porta di origine, IP di origine, porta di destinazione, IP di destinazione
Attraverso questi quattro indicatori principali, è possibile ottenere la comunicazione di rete tra le due parti. Qui non è presente alcun indirizzo IP del server perché il client e il server si trovano sullo stesso host. Possiamo utilizzare un IP per rappresentare 172.0.0.1, noto anche come IP di loopback.

1.2.4 Implementare un client UDP

public class udpEchoClient {
    private DatagramSocket socket = null;
    private String serverIp;
    private int serverProt;
    public  udpEchoClient(String serverIp, int serverProt) throws SocketException {
        socket = new DatagramSocket();
        this.serverIp = serverIp;
        this.serverProt = serverProt;
    }
    public void start() throws IOException {
        System.out.println("客户端启动!");
        //1.从控制台获取字符串
        Scanner scanner = new Scanner(System.in);
        while(true) {
            System.out.println("请输入要发送的请求: ");
            String request = scanner.nextLine();
            //2.将输入的字符串发送给服务器,还要将发送的目标确定,IP和端口号
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), 0, request.getBytes().length,
                    InetAddress.getByName(serverIp), serverProt);
            socket.send(requestPacket);
            //3.从服务器读取到经过处理的响应
            DatagramPacket responsePackt = new DatagramPacket(new byte[4096], 4096);
            socket.receive(responsePackt);
            //将响应打印在控制台
            String response = new String(responsePackt.getData(), 0, responsePackt.getLength());
            System.out.println(response);
        }
    }
    public static void main(String[] args) throws IOException {
        udpEchoClient udpEchoClient = new udpEchoClient("127.0.0.1",9999);
        udpEchoClient.start();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

Inserisci qui la descrizione dell'immagine
Per la stringa ricevuta dalla console, l'oggetto requestPacket ottiene il riferimento e la lunghezza dell'oggetto stringa, oltre al proprio IP e Prot, per poi inviarlo al server tramite il metodo send del socket.
Inserisci qui la descrizione dell'immagine
Per ricevere una risposta dal server, è necessario creare un oggetto ResponsePackt e creare anticipatamente un array di byte vuoto per ricevere la risposta ricevuta dal server.
Distinguere alcuni metodi:
Prima di distinguere i metodi, dobbiamo comprendere i concetti di byte, caratteri e forme di codifica
Byte e caratteri sono essenzialmente binari, ovvero dati come 0101, perché il computer riconosce solo 0101.
Byte: Byte è l'unità di base per la memorizzazione dei dati nel computer. 1 byte è composto da 8 bit. Ogni bit può essere 0 o 1, il che significa che un byte può rappresentare 256 valori diversi.
Carattere: il carattere è l'unità di base per rappresentare le informazioni di testo. In base alle diverse forme di codifica, il numero di byte corrispondenti a un carattere varia. Attraverso la forma di codifica, i caratteri possono essere convertiti in byte e quindi i byte possono essere utilizzati per rappresentare i dati dati e memorizzare i dati.
Modulo di codifica:

  1. Codice ASCII: utilizzato per rappresentare i caratteri inglesi.Utilizza 7 bit per rappresentare 128 caratteri (incluse lettere maiuscole e minuscole, numeri, segni di punteggiatura e alcuni caratteri di controllo), ma non supporta i caratteri cinesi. In questo caso un carattere corrisponde a un byte
  2. Unicode (UTF8): UTF-8 è un formato di codifica a lunghezza variabile che include caratteri di tutti i sistemi di scrittura del mondo. È compatibile con il set di caratteri ASCII e supporta i caratteri cinesi, inclusi i caratteri di tutti i sistemi di scrittura del mondo One il carattere corrisponde a 1-4 caratteri Festival.
  3. GBK: utilizza la codifica a lunghezza variabile, utilizzata principalmente per la codifica dei caratteri cinesi, un carattere corrisponde a 1-2 byte

I metodi sono diversi:

  1. getBytes(): ottiene un riferimento all'array di byte. L'oggetto è un carattere. Qui i caratteri vengono convertiti in byte per memorizzare i dati.
  2. getBytes().length: ottiene la lunghezza dell'array di byte, l'oggetto è un carattere
  3. getData(): ciò che si ottiene è un riferimento a una stringa composta da caratteri. L'oggetto è byte. Qui i byte vengono convertiti in caratteri per utilizzare i dati.
  4. getLength(): la lunghezza della stringa ottenuta, l'oggetto è in byte
  5. getAddress(): ottiene l'indirizzo IP, l'oggetto è DatagramPacket
  6. getPort(): ottiene il numero della porta Prot, l'oggetto è DatagramPacket
  7. getSocketAddress(): ottiene l'indirizzo IP e il numero di porta Prot, l'oggetto è DatagramPacket
  8. InetAddress.getByName(): questo metodo può analizzare il nome host e restituire l'indirizzo IP del nome host oppure restituire direttamente l'oggetto InetAddress dell'indirizzo IP specificato. L'oggetto InetAddress ottenuto viene passato al server e il server può risolverlo l'IP ottenendo questo indirizzo.

1.2.5 Implementare un server di traduzione del dizionario UDP

Qui possiamo applicare le idee di ereditarietà e polimorfismo per implementare questo server, perché la differenza essenziale tra questo server di traduzione del dizionario e il server di eco è l'elaborazione delle risposte, quindi possiamo ereditare e riutilizzare il codice ripetuto ed espandere il codice richiesto.

public class udpDictServer extends udpEchoServer{
    HashMap<String,String> map = null;
    public udpDictServer(int port) throws SocketException {
        super(port);
        map = new HashMap<>();
        map.put("server","服务");
        map.put("client","客户端");
        map.put("cat","🐱");
        map.put("dog","🐕");
        map.put("pig","🐖");
    }
    @Override
    public String process(String request) {
        return map.getOrDefault(request, "该词汇没有查询到");
    }

    public static void main(String[] args) throws IOException {
        udpDictServer udpDictServer = new udpDictServer(9999);
        udpDictServer.start();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

Per implementare questa traduzione nel dizionario, è necessaria anche una mappa nella struttura dei dati e utilizzare le coppie chiave-valore nella mappa per archiviare i dati.
Inserisci qui la descrizione dell'immagine
Quindi le operazioni aziendali specifiche devono solo riscrivere il metodo del processo.
Inserisci qui la descrizione dell'immagine
Quando si esegue qui, sebbene si riferisca all'oggetto udpEchoServer della classe genitore, poiché la sottoclasse udpDictServer eredita la classe genitore udpEchoServer e sovrascrive il metodo process, il metodo process eseguito a causa della funzionalità polimorfica è in realtà il processo del metodo sottoclasse.

2. Processo client e server

  1. Ottieni dati dalla console
  2. Il client invia i dati al server
  3. Il server riceve i dati inviati dal client
  4. Calcola la risposta
  5. Il server invia la risposta calcolata al client
  6. Il client riceve la risposta inviata dal server
  7. Stampa la risposta inviata dal server ricevuta dal client alla console