Teknologian jakaminen

【JavaEE】Verkkoohjelmointi——UDP

2024-07-12

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

Lisää kuvan kuvaus tähän
🤡🤡🤡个人主页🤡🤡🤡
🤡🤡🤡JavaEE专栏🤡🤡🤡

1. Datagram-liitäntä (UDP)

1.1 Ominaisuudet

  1. Yhteydetön: Erillistä kanavaa ei tarvitse muodostaa ennen tiedon siirtämistä. Jokainen datapaketti lähetetään itsenäisesti, ja se valitsee oman polkunsa perille täytyy saada se.
  2. Epäluotettava lähetys: Tietoa siirrettäessä sinun ei tarvitse kiinnittää huomiota siihen, onko toinen osapuoli vastaanottanut sen, vaan lähetä se.
  3. Tietovirtaan suunnattu: Tiedonsiirron perusyksikkö on jokainen UDP-datagrammi.
  4. Full-duplex: Kaksisuuntainen viestintä on mahdollista yhdellä linkillä.

1.2 Koodaus

Socket API:t ovat järjestelmän tarjoamia. Eri järjestelmien tarjoamat API:t ovat erilaisia, mutta nämä järjestelmärajapinnat on edelleen kapseloitu Javaan.
UDP:n socket-sovellusliittymä keskittyy kahteen luokkaan: DatagramSocket ja DatagramPacket

1.2.1 DatagramSocket

Tämän luokan toimintoa voidaan pitää kaukosäätimenä "verkkokortin käyttämiseen", eli verkkokortin luku- ja kirjoitustoimintoihin, jotka voidaan ymmärtää tiedostojen lukemiseksi ja kirjoittamiseksi.
Tarjolla on useita menetelmiä:
Lisää kuvan kuvaus tähän

1.2.2DatagramPacket

Tämä luokka kuvaa UDP-datagrammit DatagramPacket-objekti vastaa UDP-datagrammia Kerran lähetetty ja vastaanotettu DatagramPacket-objekti.

1.2.3 Ota käyttöön UDP (24*7) kaikupalvelin

Kaiku: Asiakas lähettää palvelimelle erilaisia ​​pyyntöjä ja palvelin palauttaa erilaisia ​​vastauksia. Mutta kaiku tässä on se, mitä asiakas pyytää palvelimelta, ja palvelin vastaa ilman laskelmia tai liiketoimintalogiikkaa.

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

Lisää kuvan kuvaus tähän
DatagramPacket-objekti edustaa datagrammia. UDP-datagrammi koostuu otsikosta ja hyötykuormasta. Otsikon IP-osoite ja porttinumero ovat DatagramPacket-luokan attribuutteja, mutta hyötykuormaluokkaa ei ole annettu, joten ohjelmoijan on tehtävä se. Edellyttäen, että kuten munkki pyytää almua, sinun on tarjottava kulho almulle, ja sitten jokainen perhe laittaa ruokaa kulhoon. Koska datagrammin olemus on binääridata, tarjoan hyötykuormana .
Lisää kuvan kuvaus tähän
Asiakkaalta saadut tiedot on palautettava asiakkaalle palvelimen käsittelyn jälkeen, joten palvelimen käsittelemien tietojen tallentamiseksi on luotava DatagramPacket-objekti, jonka jälkeen palvelin lähettää sen asiakkaalle. Tällä hetkellä DatagramPacket-objektin ei tarvitse jättää käsitellyt tiedot tähän objektiin. Koska asiakkaan IP-osoite ja porttinumero tallennetaan tietoja vastaanotettaessa, vain asiakkaan IP-osoite ja portin numero tallennetaan, kun lähetät sen asiakkaalle. Sinun on hankittava asiakkaan IP-osoite ja porttinumero requestPacket.getSocketAddress() -palvelun kautta.
Lisää kuvan kuvaus tähän
Koska palvelin on kiinteä, voit asettaa portin numeron suoraan itse. Portin numero luodaan, kun palvelin käynnistyy.
Miksi tarvitsen porttinumeron IP-osoitteen?
Jotta osapuolten välinen viestintä onnistuisi, näiden neljän keskeisen indikaattorin on oltava läsnä:
Lähdeportti, lähde-IP, kohdeportti, kohde-IP
Näiden neljän ydinindikaattorin avulla voidaan saavuttaa verkkoyhteys kahden osapuolen välillä. Tässä ei ole palvelimen IP-osoitetta, koska asiakas ja palvelin ovat samassa isännässä. Voimme käyttää IP-osoitetta edustamaan 172.0.0.1, joka tunnetaan myös nimellä loopback IP.

1.2.4 Ota käyttöön UDP-asiakas

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

Lisää kuvan kuvaus tähän
Konsolista vastaanotetulle merkkijonolle requestPacket-objekti hankkii merkkijonoobjektin viitteen ja pituuden sekä oman IP-osoitteensa ja Prot-osoitteensa ja lähettää sen sitten palvelimelle socketin lähetysmenetelmän kautta.
Lisää kuvan kuvaus tähän
Jotta saat vastauksen palvelimelta, sinun on luotava responsePackt-objekti ja luotava tyhjä tavutaulukko etukäteen vastaanottaaksesi palvelimelta saadun vastauksen.
Erota joitain menetelmiä:
Ennen menetelmien erottamista meidän on ymmärrettävä tavujen, merkkien ja koodausmuotojen käsitteet
Tavut ja merkit ovat pohjimmiltaan binaarisia, mikä on dataa, kuten 0101, koska tietokone tunnistaa vain 0101:n.
Tavu: Tavu on tietokoneen tietojen tallennuksen perusyksikkö. 1 tavu on 8 bittiä. Jokainen bitti voi olla 0 tai 1, mikä tarkoittaa, että yksi tavu voi edustaa 256 eri arvoa.
Merkki: Merkki on tekstiinformaation esittämisen perusyksikkö. Eri koodausmuotojen mukaan merkkiä vastaavien tavujen määrä on erilainen Siirrä tiedot ja tallenna tiedot.
Koodausmuoto:

  1. ASCII-koodi: käytetään edustamaan englanninkielisiä merkkejä.Se käyttää 7 bittiä edustamaan 128 merkkiä (mukaan lukien isot ja pienet kirjaimet, numerot, välimerkit ja jotkut ohjausmerkit), mutta se ei tue kiinalaisia ​​merkkejä Tässä yksi merkki vastaa yhtä tavua
  2. Unicode (UTF8): UTF-8 on muuttuvapituinen koodausmuoto, joka sisältää merkkejä kaikista kirjoitusjärjestelmistä ympäri maailmaa. Se on yhteensopiva ASCII-merkistöjen kanssa ja tukee kiinalaisia ​​merkkejä, mukaan lukien merkit kaikista kirjoitusjärjestelmistä ympäri maailmaa merkki vastaa 1-4 merkkiä.
  3. GBK: käyttää vaihtuvapituista koodausta, käytetään pääasiassa kiinalaiseen merkkikoodaukseen, yksi merkki vastaa 1-2 tavua

Menetelmät ovat erilaisia:

  1. getBytes(): Hanki viittaus tavuun. Objekti on merkki Tässä merkit muunnetaan tavuiksi tietojen tallentamiseksi.
  2. getBytes().length: Hanki tavutaulukon pituus, objekti on merkki
  3. getData(): Saatu viittaus merkkijonoon. Objekti on tavuja. Tässä tavut muunnetaan merkeiksi.
  4. getLength(): Saatu merkkijonon pituus, objekti on tavua
  5. getAddress(): Hanki IP-osoite, objekti on DatagramPacket
  6. getPort(): Hanki Prot-portin numero, objekti on DatagramPacket
  7. getSocketAddress(): Hanki IP-osoite ja Prot-portin numero, objekti on DatagramPacket
  8. InetAddress.getByName(): Tämä menetelmä voi jäsentää isäntänimen ja palauttaa isäntänimen IP-osoitteen tai palauttaa suoraan annetun IP-osoitteen InetAddress-objektin Saatu InetAddress-objekti välitetään palvelimelle, ja palvelin voi ratkaista IP hankkimalla tämän objektin.

1.2.5 Ota käyttöön UDP-sanakirjan käännöspalvelin

Tässä voimme soveltaa periytymisen ja polymorfismin ideoita tämän palvelimen toteuttamiseen, koska olennainen ero tämän sanakirjan käännöspalvelimen ja kaikupalvelimen välillä on vastausten käsittely, joten voimme periä ja käyttää uudelleen toistuvaa koodia ja laajentaa vaadittua koodia.

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

Tämän sanakirjan käännöksen toteuttamiseksi tarvitset myös kartan tietorakenteessa ja käytät kartan avainarvo-pareja tietojen tallentamiseen.
Lisää kuvan kuvaus tähän
Silloin tiettyjen liiketoimintojen tarvitsee vain kirjoittaa prosessimenetelmä uudelleen.
Lisää kuvan kuvaus tähän
Tässä suoritettaessa, vaikka tämä viittaa pääluokan udpEchoServer-olioon, koska udpDictServer-aliluokka perii udpEchoServer-emoluokan ja ohittaa prosessimenetelmän, polymorfisen ominaisuuden vuoksi suoritettu prosessimenetelmä on itse asiassa alaluokan prosessi.

2. Asiakas- ja palvelinprosessi

  1. Hae tiedot konsolista
  2. Asiakas lähettää tiedot palvelimelle
  3. Palvelin vastaanottaa asiakkaan lähettämät tiedot
  4. Laske vastaus
  5. Palvelin lähettää lasketun vastauksen asiakkaalle
  6. Asiakas saa palvelimen lähettämän vastauksen
  7. Tulostaa palvelimelta lähetetyn vastauksen, joka on vastaanotettu asiakkaalta konsoliin