day41-網路編程03
Java網路編程03
5.UDP網路通訊編程[了解]
5.1基本介紹
- 類
DatagramSocket
和DatagramPacket[數據報/數據包]
實現了基於 UDP的協議網路程式 - UDP數據報通過數據報套接字DatagramSocket 發送和接收,系統不保證UDP數據報一定能夠安全的送到目的地,也不確定什麼時候可以抵達
- DatagramPacket 對象封裝了UDP數據報,在數據報中包含了發送端的IP地址和埠號,以及接收端的IP地址和埠號
- UDP協議中每個數據報都給出了完整的的地址資訊,因此無需建立發送方和接收方的連接
UDP說明:
- 沒有明確的服務端可客戶端,演變成數據的發送端和接收端
- 接收數據和發送數據是通過DatagramSocket 對象完成的
- 將數據封裝到DatagramPacket 對象(裝包)發送
- 當接收到DatagramPacket 對象,需要進行拆包,取出數據
- DatagramSocket 可以指定在某個埠接收數據
5.2基本流程和應用案例
- 核心的兩個類/對象 DatagramSocket 與 DatagramPacket
- 建立發送端和接收端(沒有服務端和客戶端的概念)
- 建立數據報/包-DatagramPacket
- 調用DatagramSocket的發送、接收方法
- 關閉DatagramSocket
應用案例1:
- 編寫一個接收端A和一個發送端B
- 接收端A在9999埠等待接收數據(receive)
- 發送端B向接收端A 發送數據 「hello,明天吃火鍋~」
- 接收端A收到後,回復「好的,明天見」,然後退出
- 發送端B接收回復的資訊,再退出
接收端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:
啟動發送端B之後:
6.本章作業
6.1HomeWork01
- 使用字元流的方式,編寫一個客戶端程式和服務端程式
- 客戶端程式發送「name」,服務端接收到後,返回「nova」
- 客戶端發送「hobby」,服務端接收到後,返回 「打程式碼」
- 若客戶端發送的是其他資訊,則服務端回復「你說啥呢?」
- 可以循環問答
服務端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("客戶端退出..");
}
}
6.2HomeWork02
- 編寫一個接收端A和一個發送端B,使用UDP協議完成
- 接收端在8888埠等待接收數據(receive)
- 發送端向接收端 發送數據 「四大名著是哪些?」
- 接收在接收到 問題後,返回答案「《紅樓夢》《三國演義》…. 」,否則就返回 」what?「
- 接收端和發送端退出
- 最好可以循環問答
思路:
接收端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 退出");
}
}
6.3Homework03
- 編寫一個客戶端程式和服務端程式
- 客戶端可以輸入一個 音樂文件名,比如高山流水, 服務端收到音樂名後,可以給客戶端返回這個音樂文件,如果伺服器沒有這個文件,則返回一個默認的音樂即可
- 客戶端收到文件後,保存到本地d盤
- 提示:該客戶端可以使用StreamUtils.java
本質:其實就是指定下載文件的應用
思路: