day41-網路編程03

Java網路編程03

5.UDP網路通訊編程[了解]

5.1基本介紹

  1. DatagramSocket DatagramPacket[數據報/數據包]實現了基於 UDP的協議網路程式
  2. UDP數據報通過數據報套接字DatagramSocket 發送和接收,系統不保證UDP數據報一定能夠安全的送到目的地,也不確定什麼時候可以抵達
  3. DatagramPacket 對象封裝了UDP數據報,在數據報中包含了發送端的IP地址和埠號,以及接收端的IP地址和埠號
  4. UDP協議中每個數據報都給出了完整的的地址資訊,因此無需建立發送方和接收方的連接

image-20220919170633135

UDP說明:

  • 沒有明確的服務端可客戶端,演變成數據的發送端和接收端
  • 接收數據和發送數據是通過DatagramSocket 對象完成的
  • 將數據封裝到DatagramPacket 對象(裝包)發送
  • 當接收到DatagramPacket 對象,需要進行拆包,取出數據
  • DatagramSocket 可以指定在某個埠接收數據

5.2基本流程和應用案例

  1. 核心的兩個類/對象 DatagramSocket 與 DatagramPacket
  2. 建立發送端和接收端(沒有服務端和客戶端的概念)
  3. 建立數據報/包-DatagramPacket
  4. 調用DatagramSocket的發送、接收方法
  5. 關閉DatagramSocket

image-20220919171111390

應用案例1:

  1. 編寫一個接收端A和一個發送端B
  2. 接收端A在9999埠等待接收數據(receive)
  3. 發送端B向接收端A 發送數據 「hello,明天吃火鍋~」
  4. 接收端A收到後,回復「好的,明天見」,然後退出
  5. 發送端B接收回復的資訊,再退出

image-20220919171911656

接收端UDPReceiverA:

package li.network.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

//UDP接收端A
public class UDPReceiverA {
    public static void main(String[] args) throws IOException {

        // 1.創建一個DatagramSocket對象,準備在9999埠 接收 數據
        DatagramSocket datagramSocket = new DatagramSocket(9999);

        // 2.構建一個DatagramPacket對象,準備接收數據
        //因為UDP的每個數據報限制在64k內
        byte[] buf = new byte[1024];
        DatagramPacket packet = new DatagramPacket(buf, buf.length);

        //3. 調用接收方法,將通過網路傳輸的 DatagramPacket對象
        // 填充到 packet對象中
        // 當有數據報發送到本機的9999埠時,就會接收到數據
        // 如果沒有數據報發送到本機的 9999埠,就會阻塞等待
        System.out.println("接收端A 等待接收數據...");
        datagramSocket.receive(packet);

        //4.把 packet進行拆包,取出數據,並顯示
        int length = packet.getLength();//實際接收到的數據長度
        byte[] data = packet.getData();//實際接收到的數據
        String s = new String(data, 0, length);//構建字元串
        System.out.println(s);

        //5. (發送)回復消息===
        //bytes, bytes.length, InetAddress.getByName("192.168.1.6"), 8888
        //分別對應 發送的內容 內容長度 對方的ip 對發的接收埠
        byte[] bytes = "好的 明天見".getBytes();
        DatagramPacket datagramPacket =
                new DatagramPacket(bytes, bytes.length, InetAddress.getByName("192.168.1.6"), 8888);
        datagramSocket.send(datagramPacket);

        //6.關閉資源
        datagramSocket.close();
        System.out.println("A端 退出");
    }
}

發送端UDPSenderB:

package li.network.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

//發送端B====>也可以接收數據
public class UDPSenderB {
    public static void main(String[] args) throws IOException {

        //1.創建DatagramSocket ,準備在8888埠接收數據
        //這裡的埠是為了接收A回復的數據
        DatagramSocket datagramSocket = new DatagramSocket(8888);

        //2.將需要發送的數據封裝到 DatagramPacket對象
        byte[] data = "hello 明天吃火鍋".getBytes();
        //說明封裝的對象:
        // data- 內容位元組數組
        // data.length- 位元組數組的長度
        // 主機(IP)-接收方的ip
        // 9999 -對方用來接收數據的埠
        DatagramPacket datagramPacket =
                new DatagramPacket(data, data.length, InetAddress.getByName("192.168.1.6"), 9999);
        datagramSocket.send(datagramPacket);

        //3.(接收)接收回信===
        //3.1構建一個DatagramPacket對象,準備接收數據
        byte[] buf = new byte[1024];
        DatagramPacket packet = new DatagramPacket(buf, buf.length);
        //3.2調用receive接收方法,將通過網路傳輸的 DatagramPacket對象
        // 填充到 packet對象中
        // 當有數據報發送到本機的8888埠時,就會接收到數據
        // 如果沒有數據報發送到本機的 8888埠,就會阻塞等待
        datagramSocket.receive(packet);
        //拆包
        int length = packet.getLength();//實際接收到的數據長度
        byte[] bytes = packet.getData();//實際接收到的數據
        String s = new String(bytes, 0, length);//構建字元串
        System.out.println(s);

        //4.關閉資源
        datagramSocket.close();
        System.out.println("B端 退出");
    }
}

先啟動接收端A:

image-20220919175355053

啟動發送端B之後:

image-20220919175635455
image-20220919181029782

6.本章作業

6.1HomeWork01

  1. 使用字元流的方式,編寫一個客戶端程式和服務端程式
  2. 客戶端程式發送「name」,服務端接收到後,返回「nova」
  3. 客戶端發送「hobby」,服務端接收到後,返回 「打程式碼」
  4. 若客戶端發送的是其他資訊,則服務端回復「你說啥呢?」
  5. 可以循環問答

服務端Homework01Server:

package li.network.homework.homework01;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class Homework01Server {
    public static void main(String[] args) throws IOException {
        //1.服務端 在9999埠等待連接...
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("服務端:正在9999埠等待連接...");
        Socket socket = serverSocket.accept();

        BufferedReader br = null;
        BufferedWriter bw = null;
        int loop = 999;

        while ((loop--) != 0) {
            //2.服務端接收數據
            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String s = br.readLine();
            System.out.println(s);

            //3.服務端發送數據
            bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            if (s.equals("來自客戶端:你的名字?")) {
                bw.write("來自服務端:我是jack");
            } else if (s.equals("來自客戶端:你的愛好?")) {
                bw.write("來自服務端:打程式碼");
            } else {
                bw.write("來自服務端:你在說啥??");
            }
            bw.newLine();//寫入結束標誌
            bw.flush();
        }
        
        //4. 關閉流和socket
        br.close();
        bw.close();
        socket.close();
        serverSocket.close();
        System.out.println("服務端退出..");
    }
}

客戶端Homework01Client:

package li.network.homework.homework01;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;

public class Homework01Client {
    public static void main(String[] args) throws IOException {
        //1.客戶端連接服務端
        //InetAddress.getByName("192.168.1.6"),9999
        // --服務端ip和服務端的埠
        Socket socket = new Socket(InetAddress.getByName("192.168.1.6"), 9999);

        BufferedReader br = null;
        BufferedWriter bw = null;
        int loop = 999;

        while ((loop--) != 0) {
            //2.客戶端發送數據
            //從鍵盤讀取用戶問題
            Scanner scanner = new Scanner(System.in);
            System.out.println("請輸入你的問題:");
            String question = scanner.next();
            //數據 寫入 數據通道
            bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            bw.write("來自客戶端:" + question);
            bw.newLine();//結束寫入標誌
            bw.flush();

            //3.客戶端接收數據
            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String s = br.readLine();
            System.out.println(s);
        }

        //4.關閉流和socket
        bw.close();
        br.close();
        socket.close();
        System.out.println("客戶端退出..");
    }
}

image-20220919191111928 image-20220919191132296

6.2HomeWork02

  1. 編寫一個接收端A和一個發送端B,使用UDP協議完成
  2. 接收端在8888埠等待接收數據(receive)
  3. 發送端向接收端 發送數據 「四大名著是哪些?」
  4. 接收在接收到 問題後,返回答案「《紅樓夢》《三國演義》…. 」,否則就返回 」what?「
  5. 接收端和發送端退出
  6. 最好可以循環問答

思路:

image-20220919203011555

接收端Homework02ReceiverA:

package li.network.homework;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

//接收端A
public class Homework02ReceiverA {
    public static void main(String[] args) throws IOException {
        //1.創建DatagramSocket對象,指定埠
        // 9999:指定 接收數據的埠
        DatagramSocket datagramSocket = new DatagramSocket(8888);
        System.out.println("接收端A 等待接收數據...");

        int loop = 999;
        while ((loop--) != 0) {
            //2.接收資訊
            //2.1構建一個DatagramPacket對象,用來裝入接收到的 DatagramPacket
            byte[] buf = new byte[1024];
            DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length);
            //2.2使用receive接收數據
            datagramSocket.receive(datagramPacket);
            //2.3取出內容--拆包
            byte[] data = datagramPacket.getData();//真正接收到的內容
            int length = datagramPacket.getLength();//內容的長度,用於構建字元串
            String s = new String(data, 0, length);//構建字元串
            System.out.println(s);

            //3.發送回信
            byte[] databack = null;
            if (s.equals("四大名著是那些?")) {
                //封裝要發送的資訊,放到DatagramPacket對象中
                databack = "紅樓夢、三國演義、水滸傳、西遊記".getBytes();
            } else {
                databack = "what???".getBytes();
            }
            //在DatagramPacket對象指明發送的內容、長度、接收方的ip地址、接收方的埠
            DatagramPacket datagramPacket2 =
                    new DatagramPacket(databack, databack.length, InetAddress.getByName("192.168.1.6"), 9999);
            datagramSocket.send(datagramPacket2);
        }


        //4.關閉sock
        datagramSocket.close();
        System.out.println("接收端A 退出");

    }
}

發送端Homework02SenderB:

package li.network.homework;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;

//發送端B
public class Homework02SenderB {
    public static void main(String[] args) throws IOException {

        //1.創建DatagramSocket ,準備在8888埠接收數據
        //這裡的埠是為了接收A回復的數據
        DatagramSocket datagramSocket = new DatagramSocket(9999);

        int loop = 999;
        while ((loop--) != 0) {
            //2.發送數據
            //2.1從鍵盤獲取問題
            Scanner scanner = new Scanner(System.in);
            System.out.println("請輸入你的問題:");
            String question = scanner.next();
            //2.2將需要發送的數據封裝到 DatagramPacket對象
            //在DatagramPacket對象指明發送的內容、長度、接收方的ip地址、接收方的埠
            byte[] data = question.getBytes();
            DatagramPacket datagramPacket =
                    new DatagramPacket(data, data.length, InetAddress.getByName("192.168.1.6"), 8888);
            datagramSocket.send(datagramPacket);

            //3.接收數據
            //3.1先構建一個DatagramPacket對象,用來裝入接收到的 DatagramPacket
            byte[] buf = new byte[1024];
            DatagramPacket datagramPacket2 = new DatagramPacket(buf, buf.length);
            //3.2取出內容--拆包
            datagramSocket.receive(datagramPacket2);
            byte[] data2 = datagramPacket2.getData();//接收到的真正內容
            int length = datagramPacket2.getLength();//內容的長度
            String s = new String(data2, 0, length);
            System.out.println(s);
        }

        //4.關閉socket
        datagramSocket.close();
        System.out.println("發送端B 退出");

    }
}

image-20220919201921089 image-20220919201948559

6.3Homework03

  1. 編寫一個客戶端程式和服務端程式
  2. 客戶端可以輸入一個 音樂文件名,比如高山流水, 服務端收到音樂名後,可以給客戶端返回這個音樂文件,如果伺服器沒有這個文件,則返回一個默認的音樂即可
  3. 客戶端收到文件後,保存到本地d盤
  4. 提示:該客戶端可以使用StreamUtils.java

本質:其實就是指定下載文件的應用

思路:

image-20220919232143727

Tags: